From 95aab45d7de38ee32ac47f798d5996581e1f07d4 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Wed, 31 Jul 2019 14:45:03 +0200 Subject: [PATCH 01/57] Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation --- CHANGELOG-0.3.md | 12 +++ CHANGELOG.md | 2 + README.md | 11 ++- core/README.md | 5 -- core/src/epicli/README.md | 1 - core/src/epicli/setup.py | 4 +- .../playground/epiphany-playground.png | 3 - docs/architecture/docs/README.md | 5 -- docs/architecture/docs/index.md | 3 - docs/home/COMPONENTS.md | 27 +++++++ docs/home/LICENSES.md | 39 --------- docs/home/RESOURCES.md | 79 ++++++++++--------- 12 files changed, 95 insertions(+), 96 deletions(-) delete mode 100644 core/README.md delete mode 100644 core/src/epicli/README.md delete mode 100644 docs/architecture/diagrams/playground/epiphany-playground.png delete mode 100644 docs/architecture/docs/README.md delete mode 100644 docs/architecture/docs/index.md create mode 100644 docs/home/COMPONENTS.md delete mode 100644 docs/home/LICENSES.md diff --git a/CHANGELOG-0.3.md b/CHANGELOG-0.3.md index bb7e71750b..458d9ebb36 100644 --- a/CHANGELOG-0.3.md +++ b/CHANGELOG-0.3.md @@ -4,6 +4,18 @@ ### Added +- Support for AWS cloud (or AWS platform or AWS cloud platform) +- New Python based CLI - epicli. Currently supports AWS and baremetal deployments only +- Kubernetes automatic upgrade (experimental) +- Server spec tests for cluster components +- Added Canal as network plugin for Kubernetes +- Improved security + ### Changed +- Kubernetes version 1.14.4 +- Documentation cleanup and updates + ### Fixed + +- Fixed vulnerabilities for KeyCloak examples diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e882dde7..341b42f495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in linked files. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +Reference for actual cluster component versions can be found [here](docs/home/COMPONENTS.md) + ## Current release ### 0.3.x diff --git a/README.md b/README.md index b0b11207dc..0165763cf7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,14 @@ ## Overview -Epiphany at its core is a full automation of Kubernetes and Docker plus additional builtin services such as Kafka for high speed messaging/events, Prometheus for monitoring and Graphana for dashboards, Elasticsearch and Kibana for centralized logging. Other optional services are being evaluated now. +Epiphany at its core is a full automation of Kubernetes and Docker plus additional builtin services/components like: + +- Kafka or RabbitMQ for high speed messaging/events +- Prometheus and Alertmanager for monitoring with Graphana for visualization +- Elasticsearch and Kibana for centralized logging +- HAProxy for loadbalancing +- Postgress for storage +- KeyCloak for authentication Epiphany can run on as few as one node (laptop, desktop, server) but the real value comes from running 3 or more nodes for scale and HA. Nodes can be added or removed at will depending on data in the manifest. Everything is data driven so simply changing the manifest data and running the automation will modify the environment. @@ -75,7 +82,7 @@ Find more information using table of contents below - especially the [How-to gui - [How-to contribute](docs/home/CONTRIBUTING.md) - [Workflow to follow](docs/home/GITWORKFLOW.md) - [Governance model](docs/home/GOVERNANCE.md) - - [Licenses](docs/home/LICENSES.md) + - [Components](docs/home/COMPONENTS.md) - [Changelog](CHANGELOG.md) diff --git a/core/README.md b/core/README.md deleted file mode 100644 index 29e95a9ad9..0000000000 --- a/core/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Core - -This folder contains the Epiphany core. - -For the full story, go to [Epiphany documentation](../README.md). \ No newline at end of file diff --git a/core/src/epicli/README.md b/core/src/epicli/README.md deleted file mode 100644 index 30404ce4c5..0000000000 --- a/core/src/epicli/README.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/core/src/epicli/setup.py b/core/src/epicli/setup.py index fc49d5e933..f570704ad4 100644 --- a/core/src/epicli/setup.py +++ b/core/src/epicli/setup.py @@ -4,10 +4,10 @@ from cli.version import VERSION import os -with open('README.md') as f: +with open('../../../README.md') as f: readme = f.read() -with open('LICENSE') as f: +with open('../../../LICENSE') as f: license = f.read() with open('requirements.txt') as f: diff --git a/docs/architecture/diagrams/playground/epiphany-playground.png b/docs/architecture/diagrams/playground/epiphany-playground.png deleted file mode 100644 index d03d1e0cbc..0000000000 --- a/docs/architecture/diagrams/playground/epiphany-playground.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3f37b75ce1ff3fe8f990e1b894c6276337eb62572d8b0fb350462ae3b554390b -size 213504 diff --git a/docs/architecture/docs/README.md b/docs/architecture/docs/README.md deleted file mode 100644 index 9d1d2dcc61..0000000000 --- a/docs/architecture/docs/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Architecture Documentation - -This section contains Architecture Design Documents. These help provide context on why certain technical decisions were made and why certain tools were made. - -You can check out the [primary documentation](/docs/index.md) for details or the [index](index.md) here in this folder. diff --git a/docs/architecture/docs/index.md b/docs/architecture/docs/index.md deleted file mode 100644 index 7696d6257c..0000000000 --- a/docs/architecture/docs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Architecture Index - -Documentation index. diff --git a/docs/home/COMPONENTS.md b/docs/home/COMPONENTS.md new file mode 100644 index 0000000000..382764b222 --- /dev/null +++ b/docs/home/COMPONENTS.md @@ -0,0 +1,27 @@ +# Licenses of Epiphany component dependencies + +Note that versions are default versions and can be changed in certain cases through configuration. Versions that are marked with '-' are dependent on the OS distribution version and packagemanager. + +| Component | Version | Repo/Website | License | +| --------------------- | ------- | ----------------------------------------------------- | ----------------------------------------------------------------- | +| Kubernetes | 1.14.4 | https://github.com/kubernetes/kubernetes | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Calico | - | https://github.com/projectcalico/calico | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Flannel | - | https://github.com/coreos/flannel/ | [Apache License](https://www.apache.org/licenses/LICENSE-1.0) | +| Canal | - | https://github.com/projectcalico/calico | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Kafka | 2.0.0 | https://github.com/apache/kafka | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Zookeeper | 3.4.12 | https://github.com/apache/zookeeper | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| RabbitMQ | 3.7.10 | https://github.com/rabbitmq/rabbitmq-server | [Mozilla Public License](https://www.mozilla.org/en-US/MPL/) | +| Docker-ce | 18.09.6 | https://github.com/docker/docker-ce/ | [Apache License](https://www.apache.org/licenses/LICENSE-1.0) | +| KeyCloak | 4.8.3 | https://github.com/keycloak/keycloak | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Elasticsearch | 6.4.0 | https://github.com/elastic/elasticsearch | https://github.com/elastic/elasticsearch/blob/master/LICENSE.txt | +| Elasticsearch Curator | 5.5.4 | https://github.com/elastic/curator | https://github.com/elastic/curator/blob/master/LICENSE.txt | +| Kibana | 6.5.4 | https://github.com/elastic/kibana | https://github.com/elastic/kibana/blob/master/LICENSE.txt | +| Filebeat | 2.10.0 | https://github.com/elastic/beats/tree/master/filebeat | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Prometheus | 6.2.5 | https://github.com/prometheus/prometheus | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| Grafana | - | https://github.com/grafana/grafana | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| node_exporter | 0.16.0 | https://github.com/prometheus/node_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| kafka_exporter | 1.2.0 | https://github.com/danielqsj/kafka_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| haproxy_exporter | 0.10.0 | https://github.com/prometheus/haproxy_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| jmx_exporter | 0.12.0 | https://github.com/prometheus/jmx_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | +| PostgresSQL | 10 | https://www.postgresql.org/ | https://opensource.org/licenses/postgresql | +| HAProxy | 1.8 | https://www.haproxy.org/ | [GNU General Public License 2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)| | diff --git a/docs/home/LICENSES.md b/docs/home/LICENSES.md deleted file mode 100644 index 0883fba900..0000000000 --- a/docs/home/LICENSES.md +++ /dev/null @@ -1,39 +0,0 @@ -# Licenses of Epiphany component dependencies - -| Component | Repo/Website | License | -| --------------------- | ----------------------------------------------------- | ----------------------------------------------------------------- | -| Kubernetes | https://github.com/kubernetes/kubernetes | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| Calico | https://github.com/projectcalico/calico | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| Flannel | https://github.com/coreos/flannel/ | [Apache License](https://www.apache.org/licenses/LICENSE-1.0) | -| Kafka | https://github.com/apache/kafka | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| Zookeeper | https://github.com/apache/zookeeper | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| RabbitMQ | https://github.com/rabbitmq/rabbitmq-server | [Mozilla Public License](https://www.mozilla.org/en-US/MPL/) | -| Docker-ce | https://github.com/docker/docker-ce/ | [Apache License](https://www.apache.org/licenses/LICENSE-1.0) | -| Elasticsearch | https://github.com/elastic/elasticsearch | https://github.com/elastic/elasticsearch/blob/master/LICENSE.txt | -| Elasticsearch Curator | https://github.com/elastic/curator | https://github.com/elastic/curator/blob/master/LICENSE.txt | -| Kibana | https://github.com/elastic/kibana | https://github.com/elastic/kibana/blob/master/LICENSE.txt | -| Filebeat | https://github.com/elastic/beats/tree/master/filebeat | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| Prometheus | https://github.com/prometheus/prometheus | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| Grafana | https://github.com/grafana/grafana | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| node_exporter | https://github.com/prometheus/node_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| kafka_exporter | https://github.com/danielqsj/kafka_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| haproxy_exporter | https://github.com/prometheus/haproxy_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| jmx_exporter | https://github.com/prometheus/jmx_exporter | [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) | -| PostgresSQL | https://www.postgresql.org/ | https://opensource.org/licenses/postgresql | -| HAProxy | https://www.haproxy.org/ | [GNU General Public License 2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)| | - - - - - - - - - - - - - - - - diff --git a/docs/home/RESOURCES.md b/docs/home/RESOURCES.md index 9815606105..49b122ca87 100644 --- a/docs/home/RESOURCES.md +++ b/docs/home/RESOURCES.md @@ -1,42 +1,49 @@ # Resources -Here are some materials concerning Epiphany components - both on what we use in the background and on what's available for you to use with your application/deployment. Links for every component are in an ascending order of complexity. +Here are some materials concerning Epiphany tooling and cluster components - both on what we use in the background and on what's available for you to use with your application/deployment. -1. Under the hood - 1. [Terraform](https://www.terraform.io/) - - AWS use case [example](https://www.terraform.io/intro/getting-started/build.html) - 2. [Ansible](https://www.ansible.com/) - - [Intro to playbooks](https://docs.ansible.com/ansible/2.5/user_guide/playbooks_intro.html) - 3. [jq](https://stedolan.github.io/jq) -2. Available out of the box - 1. [Docker](https://www.docker.com/) - - (Pluralsight) [Introduction to Docker and containerization](https://app.pluralsight.com/library/courses/docker-containers-big-picture/table-of-contents) - - [A Beginner-Friendly Introduction to Containers, VMs and Docker](https://medium.freecodecamp.org/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b) - 2. [Kubernetes](https://kubernetes.io/) - - (Pluralsight) [Introduction to Kubernetes](https://app.pluralsight.com/library/courses/getting-started-kubernetes/table-of-contents) - - [Kubernetes Basics](https://kubernetes.io/docs/tutorials/kubernetes-basics/) - - (Free Udacity course) [Scalable Microservices with Kubernetes](https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615) - - Curated list of [Kubernetes resources](https://legacy.gitbook.com/book/ramitsurana/awesome-kubernetes/details) - 3. Monitoring - 1. [Prometheus](https://prometheus.io/) - - Query [examples](https://prometheus.io/docs/prometheus/latest/querying/examples/) - - [Integration with Grafana](https://prometheus.io/docs/visualization/grafana/) - - Included [OS mectric collector](https://github.com/prometheus/node_exporter) - - Kafka monitoring with [JMX exporter](https://github.com/prometheus/jmx_exporter) - - Alertmanager [Alerts from Prometheus](https://prometheus.io/docs/alerting/alertmanager/) - 2. [Grafana](https://grafana.com/) - - Community supplied, ready to use [dashboards](https://grafana.com/dashboards) - 4. [Kafka](http://kafka.apache.org/) +## Tooling + +1. [Python 3.7](https://docs.python.org/3.7/) + - [Docs and tutorials](https://docs.python.org/3/tutorial/) +2. [Terraform](https://www.terraform.io/) + - AWS use case [example](https://www.terraform.io/intro/getting-started/build.html) +3. [Ansible](https://www.ansible.com/) + - [Intro to playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html) + +## Cluster Components + +1. [Docker](https://www.docker.com/) + - (Pluralsight) [Introduction to Docker and containerization](https://app.pluralsight.com/library/courses/docker-containers-big-picture/table-of-contents) + - [A Beginner-Friendly Introduction to Containers, VMs and Docker](https://medium.freecodecamp.org/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b) +2. [Kubernetes](https://kubernetes.io/) + - (Pluralsight) [Introduction to Kubernetes](https://app.pluralsight.com/library/courses/getting-started-kubernetes/table-of-contents) + - [Kubernetes Basics](https://kubernetes.io/docs/tutorials/kubernetes-basics/) + - (Free Udacity course) [Scalable Microservices with Kubernetes](https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615) + - Curated list of [Kubernetes resources](https://legacy.gitbook.com/book/ramitsurana/awesome-kubernetes/details) +3. Monitoring + 1. [Prometheus](https://prometheus.io/) + - Query [examples](https://prometheus.io/docs/prometheus/latest/querying/examples/) + - [Integration with Grafana](https://prometheus.io/docs/visualization/grafana/) + - Included [OS mectric collector](https://github.com/prometheus/node_exporter) + - Kafka monitoring with [JMX exporter](https://github.com/prometheus/jmx_exporter) + - Alertmanager [Alerts from Prometheus](https://prometheus.io/docs/alerting/alertmanager/) + 2. [Grafana](https://grafana.com/) + - Community supplied, ready to use [dashboards](https://grafana.com/dashboards) +4. Messaging + 1. [Kafka](http://kafka.apache.org/) - [Kafka introduction](http://kafka.apache.org/intro) - (Pluralsight) [Getting Started with Apache Kafka](https://app.pluralsight.com/library/courses/apache-kafka-getting-started/table-of-contents) - 5. [RabbitMQ](https://www.rabbitmq.com/) + 2. [RabbitMQ](https://www.rabbitmq.com/) - [RabbitMQ Getting started](https://www.rabbitmq.com/getstarted.html) - 6. Central logging - 1. [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) - 2. [Kibana](https://www.elastic.co/guide/en/kibana/current/index.html) - 3. [Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/index.html) - - Beats platform reference(https://www.elastic.co/guide/en/beats/libbeat/current/index.html) - 7. Load Balancing - 1. [HaProxy](http://www.haproxy.org/) - 8. Databases - 1. [PostgreSQL](https://www.postgresql.org/docs/) \ No newline at end of file +5. Central logging + 1. [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) + 2. [Kibana](https://www.elastic.co/guide/en/kibana/current/index.html) + 3. [Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/index.html) + - Beats platform reference(https://www.elastic.co/guide/en/beats/libbeat/current/index.html) +6. Load Balancing + 1. [HaProxy](http://www.haproxy.org/) +7. Databases + 1. [PostgreSQL](https://www.postgresql.org/docs/) +8. Authentication + 1. [KeyCloak](https://www.keycloak.org/documentation.html) From 601c62a5c7c43e0902b5b67ee87e2de8306a4875 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Wed, 31 Jul 2019 15:56:01 +0200 Subject: [PATCH 02/57] Fixed links. --- docs/home/HOWTO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index 9f5aa19de0..437ab14bb0 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -9,8 +9,8 @@ - [Epicli development](#epicli-development) - [Legacy](#legacy) - [Run directly from OS](#run-directly-from-os) - - [Run Docker image for development](#run-with-image-for-development) - - [Run Docker image for deployment](#run-with-image-for-deployment) + - [Run Docker image for development](#run-docker-image-for-development) + - [Run Docker image for deployment](#run-docker-image-for-deployment) - [Note for Windows users](#note-for-windows-users) - Epiphany cluster - [How to create an Epiphany cluster on premise](#how-to-create-an-epiphany-cluster-on-premise) From a4c9065e86613b9ca98d8e10c990b486393ab58b Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Wed, 31 Jul 2019 16:02:01 +0200 Subject: [PATCH 03/57] Fixed changelog. --- CHANGELOG-0.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-0.3.md b/CHANGELOG-0.3.md index 458d9ebb36..4210501f5e 100644 --- a/CHANGELOG-0.3.md +++ b/CHANGELOG-0.3.md @@ -4,7 +4,7 @@ ### Added -- Support for AWS cloud (or AWS platform or AWS cloud platform) +- Support for AWS cloud platform - New Python based CLI - epicli. Currently supports AWS and baremetal deployments only - Kubernetes automatic upgrade (experimental) - Server spec tests for cluster components From e94b6787bd580dba8ae0c3abb380faef97b9b48b Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Thu, 1 Aug 2019 13:39:22 +0200 Subject: [PATCH 04/57] Added node_exporter port known issue. --- CHANGELOG-0.3.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-0.3.md b/CHANGELOG-0.3.md index 7f771f791a..be8dcba995 100644 --- a/CHANGELOG-0.3.md +++ b/CHANGELOG-0.3.md @@ -22,4 +22,5 @@ ### Known issues -- Deployment/Application role failes because Kubernetes cluster is not ready after reboot. More info [here](https://github.com/epiphany-platform/epiphany/issues/407) \ No newline at end of file +- Deployment/Application role fails because Kubernetes cluster is not ready after reboot. More info [here](https://github.com/epiphany-platform/epiphany/issues/407) +- Node_exporter ports are not present in defaults resulting in Prometheus not beeing able to scrape data with minimal cluster data.yaml. More info [here](https://github.com/epiphany-platform/epiphany/issues/410) \ No newline at end of file From d350a76d36472ab6cddd16f9bfebd90567d81e5d Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Mon, 5 Aug 2019 14:48:03 +0200 Subject: [PATCH 05/57] Added new terraform-bin plugin and updated templates to 0.12.6 (#418) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * Added new terraform-bin plugin and updated templates to 0.12.6 --- core/src/epicli/Pipfile | 2 +- core/src/epicli/Pipfile.lock | 99 ++++++++++--------- .../defaults/infrastructure/efs-storage.yml | 4 +- .../infrastructure/virtual-machine.yml | 12 +-- .../terraform/infrastructure/efs-storage.j2 | 2 +- .../infrastructure/internet-gateway.j2 | 2 +- .../infrastructure/launch-configuration.j2 | 12 +-- .../terraform/infrastructure/route-table.j2 | 2 +- .../infrastructure/security-group.j2 | 2 +- .../data/aws/terraform/infrastructure/vpc.j2 | 2 +- 10 files changed, 70 insertions(+), 69 deletions(-) diff --git a/core/src/epicli/Pipfile b/core/src/epicli/Pipfile index 2ea1c9c864..71b04fb11d 100644 --- a/core/src/epicli/Pipfile +++ b/core/src/epicli/Pipfile @@ -16,7 +16,7 @@ boto3 = "*" jsonschema = "*" python-json-logger = "*" ansible = "*" -terraform-binary = "*" +terraform-bin = "*" [requires] python_version = "3.7" diff --git a/core/src/epicli/Pipfile.lock b/core/src/epicli/Pipfile.lock index 04fbf71bfd..8e4dcaa976 100644 --- a/core/src/epicli/Pipfile.lock +++ b/core/src/epicli/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5eac281bc387f8394939091459143b61e2631850bcdd14eeed680d2a06385765" + "sha256": "b528cc683e3bdc332aae79a02b9a941f936cb790e13580d677495f989d693128" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "ansible": { "hashes": [ - "sha256:e1d51d3a88e21238f9e7a49b2b17a49e76c13880242b936ac8a37aee4fe84445" + "sha256:05f9ed3ca3e06dffaa87a73a8e6f7f322825bc3f609f8b71c4fe22dbbdf72abc" ], "index": "pypi", - "version": "==2.8.1" + "version": "==2.8.3" }, "asn1crypto": { "hashes": [ @@ -39,18 +39,18 @@ }, "boto3": { "hashes": [ - "sha256:050e855eb034df38e737c9598ef74610b7a2912bddb8db00a30596e3c75bd482", - "sha256:af3992dc2e99b6d062dfc97afce93695058430b3ba7d59ce42b78e6ae09b8003" + "sha256:0cd4a3e158f40eedb54b36b3fbe60d135db74a245f0ca8eead1af2eb6d46a649", + "sha256:68e9eba6f846cf8e01973ec565afdb1adfb9612b531c15bb5c5524394db4df5b" ], "index": "pypi", - "version": "==1.9.182" + "version": "==1.9.199" }, "botocore": { "hashes": [ - "sha256:1482cfa725bb1b678e02b006f15cb966ff5c3a20c2d9b0aff946056bd6baf152", - "sha256:d1e556a130baca5719192031732c96c2455322369719ac4304ff5044b347d847" + "sha256:25d87047241b7b775443570c0e790ca952f9f7491d4d6472430a4b006383a257", + "sha256:e4729c1acaa936d4c5c948a18d279f92bbf61fad9b5fb03942c753ec405e427d" ], - "version": "==1.12.182" + "version": "==1.12.199" }, "cffi": { "hashes": [ @@ -131,11 +131,11 @@ }, "jsonschema": { "hashes": [ - "sha256:0c0a81564f181de3212efa2d17de1910f8732fa1b71c42266d983cd74304e20d", - "sha256:a5f6559964a3851f59040d3b961de5e68e70971afb88ba519d27e6a039efff1a" + "sha256:5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f", + "sha256:8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d" ], "index": "pypi", - "version": "==3.0.1" + "version": "==3.0.2" }, "markupsafe": { "hashes": [ @@ -172,16 +172,15 @@ }, "pycparser": { "hashes": [ - "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3", - "sha256:d47687b1c43981ae0999ae87c3658ef22339086ffd36353611e783746f7d5601" + "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" ], "version": "==2.19" }, "pyrsistent": { "hashes": [ - "sha256:16692ee739d42cf5e39cef8d27649a8c1fdb7aa99887098f1460057c5eb75c3a" + "sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533" ], - "version": "==0.15.2" + "version": "==0.15.4" }, "python-dateutil": { "hashes": [ @@ -200,20 +199,22 @@ }, "pyyaml": { "hashes": [ - "sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3", - "sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043", - "sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7", - "sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265", - "sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391", - "sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778", - "sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225", - "sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955", - "sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e", - "sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190", - "sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd" + "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", + "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", + "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", + "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", + "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", + "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", + "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", + "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", + "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", + "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", + "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", + "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", + "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" ], "index": "pypi", - "version": "==5.1.1" + "version": "==5.1.2" }, "s3transfer": { "hashes": [ @@ -229,12 +230,12 @@ ], "version": "==1.12.0" }, - "terraform-binary": { + "terraform-bin": { "hashes": [ - "sha256:3f525447e5fa9dbe20988d18c54acd926abe30619059870ce94179326adbbda5" + "sha256:af59ff1e59f620b7db88fd11411572aeab406d0759caa6028eaa01b9b3a9fc01" ], "index": "pypi", - "version": "==0.11.11.post1" + "version": "==1.0.1" }, "urllib3": { "hashes": [ @@ -298,24 +299,24 @@ }, "importlib-metadata": { "hashes": [ - "sha256:6dfd58dfe281e8d240937776065dd3624ad5469c835248219bd16cf2e12dbeb7", - "sha256:cb6ee23b46173539939964df59d3d72c3e0c1b5d54b84f1d8a7e912fe43612db" + "sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", + "sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3" ], - "version": "==0.18" + "version": "==0.19" }, "more-itertools": { "hashes": [ - "sha256:3ad685ff8512bf6dc5a8b82ebf73543999b657eded8c11803d9ba6b648986f4d", - "sha256:8bb43d1f51ecef60d81854af61a3a880555a14643691cc4b64a6ee269c78f09a" + "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", + "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" ], - "version": "==7.1.0" + "version": "==7.2.0" }, "packaging": { "hashes": [ - "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", - "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" ], - "version": "==19.0" + "version": "==19.1" }, "pkginfo": { "hashes": [ @@ -347,18 +348,18 @@ }, "pyparsing": { "hashes": [ - "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", - "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" ], - "version": "==2.4.0" + "version": "==2.4.2" }, "pytest": { "hashes": [ - "sha256:2878de8ae1c79a62c012da6186b88ff0562ea96ce29c4208d2a9b11d9f607df1", - "sha256:95b700cf21ed5b7e91bce7a6b5a573b2e3ef7b3643d00f681d8f9c4672f9fbdf" + "sha256:6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", + "sha256:a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77" ], "index": "pypi", - "version": "==5.0.0" + "version": "==5.0.1" }, "readme-renderer": { "hashes": [ @@ -435,10 +436,10 @@ }, "zipp": { "hashes": [ - "sha256:8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d", - "sha256:ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3" + "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", + "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec" ], - "version": "==0.5.1" + "version": "==0.5.2" } } } diff --git a/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml b/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml index 7cfcc6ead0..73053e90ae 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml @@ -6,7 +6,7 @@ name: default specification: name: SET_BY_AUTOMATION token: SET_BY_AUTOMATION - encrypted: True + encrypted: true performance_mode: "generalPurpose" throughput_mode: "bursting" #provisioned_throughput_in_mibps: # The throughput, measured in MiB/s, that you want to provision for the file system. Only applicable when throughput_mode set to provisioned @@ -14,5 +14,5 @@ specification: # - name: mount-name # subnet_name: source_subnet_name security: - populate_sg_rules: True # when set to true, security group for EFS will allow traffic from other clusters, groups + populate_sg_rules: true # when set to true, security group for EFS will allow traffic from other clusters, groups diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 742decea2c..917569f8e6 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -10,8 +10,8 @@ specification: availability_zones: [] # specified automatically - based on subnet az's launch_configuration: SET_BY_AUTOMATION cluster_name: SET_BY_AUTOMATION - authorized_to_efs: False - mount_efs: False + authorized_to_efs: false + mount_efs: false tags: - version: 0.3.0 size: t2.micro @@ -71,8 +71,8 @@ provider: aws name: kubernetes-master-machine specification: size: t3.medium - authorized_to_efs: True - mount_efs: True + authorized_to_efs: true + mount_efs: true security: rules: - name: ssh @@ -151,8 +151,8 @@ provider: aws name: kubernetes-node-machine specification: size: t3.medium - authorized_to_efs: True - mount_efs: True + authorized_to_efs: true + mount_efs: true security: rules: - name: ssh diff --git a/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 b/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 index 3f1bc20ccb..a98be6c7e8 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 @@ -12,7 +12,7 @@ resource "aws_efs_file_system" "{{ specification.name }}" { creation_token = "{{ specification.token }}" - encrypted = "{{ specification.encrypted }}" + encrypted = "{{ specification.encrypted | lower }}" performance_mode = "{{ specification.performance_mode }}" throughput_mode = "{{ specification.throughput_mode }}" diff --git a/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 b/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 index 8ce76dc6f9..52a0f4d099 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 @@ -13,7 +13,7 @@ resource "aws_internet_gateway" "{{ specification.name }}" { vpc_id = "${aws_vpc.{{ specification.vpc_name }}.id}" - tags { + tags = { Name = "{{ specification.name }}" cluster_name = "{{ specification.cluster_name }}" cluster_version = "{{ version }}" diff --git a/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 b/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 index f3539fb618..f4687ad76c 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 @@ -15,18 +15,18 @@ resource "aws_launch_configuration" "{{ specification.name }}" { name = "{{ specification.name }}" image_id = "{{ specification.image_id }}" instance_type = "{{ specification.size }}" - associate_public_ip_address = "{{ specification.associate_public_ip }}" + associate_public_ip_address = "{{ specification.associate_public_ip | lower }}" # Security group security_groups = [{% for security_group in specification.security_groups %} "${aws_security_group.{{ security_group }}.id}" {% if not loop.last %}, {% endif %} {% endfor %}] - enable_monitoring = "{{ specification.enable_monitoring }}" + enable_monitoring = "{{ specification.enable_monitoring | lower }}" key_name = "{{ specification.key_name }}" - ebs_optimized = "{{ specification.ebs_optimized }}" + ebs_optimized = "{{ specification.ebs_optimized | lower }}" root_block_device { volume_type = "{{ specification.disks.root.volume_type }}" volume_size = "{{ specification.disks.root.volume_size }}" - delete_on_termination = "{{ specification.disks.root.delete_on_termination }}" + delete_on_termination = "{{ specification.disks.root.delete_on_termination | lower }}" } {% for disk in specification.disks.additional_disks %} @@ -35,8 +35,8 @@ resource "aws_launch_configuration" "{{ specification.name }}" { device_name = "{{ disk.device_name }}" volume_type = "{{ disk.volume_type }}" volume_size = "{{ disk.volume_size }}" - encrypted = "{{ disk.encrypted }}" - delete_on_termination = "{{ disk.delete_on_termination }}" + encrypted = "{{ disk.encrypted | lower }}" + delete_on_termination = "{{ disk.delete_on_termination | lower }}" } {%- endfor %} diff --git a/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 b/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 index 8c596fc01b..f7143b3e5e 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 @@ -18,7 +18,7 @@ resource "aws_route_table" "{{ specification.name }}" { gateway_id = "${ aws_internet_gateway.{{ specification.route.gateway_name }}.id}" } - tags { + tags = { Name = "web-table" cluster_name = "{{ specification.cluster_name }}" cluster_version = "{{ version }}" diff --git a/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 b/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 index 92ab12efdd..4db45f6c9a 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 @@ -16,7 +16,7 @@ resource "aws_security_group" "{{ specification.name }}" { vpc_id = "${aws_vpc.{{ specification.vpc_name }}.id}" - tags { + tags = { cluster_name = "{{ specification.cluster_name }}" cluster_version = "{{ version }}" } diff --git a/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 b/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 index 0bf6df0375..a103ffd1c1 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 @@ -16,7 +16,7 @@ resource "aws_vpc" "{{ specification.name }}" { enable_dns_support = "true" enable_dns_hostnames = "true" - tags { + tags = { Name = "{{ specification.name }}" cluster_name = "{{ specification.cluster_name }}" cluster_version = "{{ version }}" From aed56ba248b59e3f62319c24efd80a343bc7cc98 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Mon, 5 Aug 2019 14:52:46 +0200 Subject: [PATCH 06/57] Fix/ports security groups aws for defaults (#417) * Item: #410 Desc: Add ports for node_exporter and kafka_exporter * Item: #470 Desc: Add machine type for load balancer with opened ports for haproxy * Item: #410 Desc: Add new ports to haproxy exporter --- .../infrastructure/virtual-machine.yml | 137 +++++++++++++++++- .../data/common/defaults/epiphany-cluster.yml | 2 +- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 917569f8e6..360c58af7d 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -63,6 +63,71 @@ specification: - version: 0.3.0 size: t3.micro os_type: linux + security: + rules: + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: aws +name: load-balancer-machine +specification: + tags: + - version: 0.3.0 + size: t3.micro + os_type: linux + security: + rules: + - name: ssh + description: Allow ssh traffic + priority: 101 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: haproxy_exporter + description: Allow haproxy_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9101" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Egress + access: Allow + protocol: "all" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 @@ -85,6 +150,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: subnet-traffic description: Allow subnet traffic priority: 102 @@ -165,6 +240,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: subnet-traffic description: Allow master subnet traffic priority: 102 @@ -231,6 +316,26 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: kafka_exporter + description: Allow kafka exporter traffic + priority: 303 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9308" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: zookeeper1 description: Allow Zookeeper 1 priority: 102 @@ -337,6 +442,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 @@ -367,6 +482,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 @@ -421,6 +546,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: Elastic description: Allow Elastic priority: 105 @@ -460,4 +595,4 @@ specification: source_port_range: "*" destination_port_range: "0" source_address_prefix: "0.0.0.0/0" - destination_address_prefix: "0.0.0.0/0" \ No newline at end of file + destination_address_prefix: "0.0.0.0/0" diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 364f38d887..783e34901a 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -67,7 +67,7 @@ specification: load_balancer: count: 1 - machine: default + machine: load-balancer-machine configuration: default subnets: - availability_zone: eu-west-2a From 18c2af2c580a67f9ea0d3945814f87fbe821e395 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Mon, 5 Aug 2019 16:27:29 +0200 Subject: [PATCH 07/57] Documentation - users and groups created directly by Epiphany (#420) * Item: #410 Desc: Add ports for node_exporter and kafka_exporter * Item: #274 Desc: List security users and groups created directly by Epiphany * Item: #000 Desc: Fix after merge --- docs/home/SECURITY.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/home/SECURITY.md diff --git a/docs/home/SECURITY.md b/docs/home/SECURITY.md new file mode 100644 index 0000000000..ee57fdd114 --- /dev/null +++ b/docs/home/SECURITY.md @@ -0,0 +1,23 @@ +# Security related information + +## Contents + +- [Users and roles created by epiphany](#users-and-roles-created-by-epiphany) + + + +### Users and roles created by epiphany + +By default Epiphany is creating user operations that is used to connect to machines with admin rights. This setting can +be changed in Epiphany yaml configuration files. + +Additional to users created by each component Epiphany creates also users and groups: + - haproxy_exporter/haproxy_exporter + - kafka_exporter/kafka_exporter + - node_exporter/node_exporter + - jmx-exporter/jmx-exporter + - prometheus/prometheus + - rabbitmq/rabbitmq + - zookeeper/zookeeper + - kafka/kafka + From 7b529b356f98d2667061ef79677fa35c5fdd3274 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Tue, 6 Aug 2019 12:34:21 +0200 Subject: [PATCH 08/57] Removing the test environment destruction function (#421) --- core/src/epicli/tests/docker/test-ci-epicli/run.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/core/src/epicli/tests/docker/test-ci-epicli/run.sh b/core/src/epicli/tests/docker/test-ci-epicli/run.sh index d0c2f9d882..b7c81b98b8 100644 --- a/core/src/epicli/tests/docker/test-ci-epicli/run.sh +++ b/core/src/epicli/tests/docker/test-ci-epicli/run.sh @@ -1,18 +1,9 @@ #!/bin/bash - -function destroyEnvironment { - cd "/shared/$CLUSTER_NAME/terraform" - terraform init - terraform destroy -auto-approve -} - echo "Starting Epiphany build for cluster $CLUSTER_NAME" epicli apply -f "/shared/$CLUSTER_NAME/$CLUSTER_NAME.yml" -status=$? - -if [[ $status -eq 0 ]] +if [[ $? -eq 0 ]] then echo echo "Epiphany build for cluster $CLUSTER_NAME completed successfully" @@ -20,11 +11,10 @@ then echo "Serverspec tests for cluster $CLUSTER_NAME started..." rake inventory="/shared/$CLUSTER_NAME/inventory" user=$ADMIN_USERNAME keypath=$KEY_PATH spec:all echo "Serverspec tests for cluster $CLUSTER_NAME finished" - destroyEnvironment echo else echo echo "Epiphany build for cluster $CLUSTER_NAME FAILED!" - destroyEnvironment + echo exit 1 fi From 9e8a4edae0c546e9584a2c43e71b7bf06268a1a0 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Tue, 6 Aug 2019 14:35:54 +0200 Subject: [PATCH 09/57] Opened ports documentation (#423) * Item: #410 Desc: Add ports for node_exporter and kafka_exporter * Item: #274 Desc: List ports used by Epiphany in documentation. * Item: #000 Desc: Fix after merge * Item: #274 Desc: Changes required by pull request - remove TCP from docs for kubernetes * Item: #274 Desc: Changes required by pull request - information about defaults --- docs/home/SECURITY.md | 70 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/docs/home/SECURITY.md b/docs/home/SECURITY.md index ee57fdd114..d5f10e3859 100644 --- a/docs/home/SECURITY.md +++ b/docs/home/SECURITY.md @@ -2,8 +2,8 @@ ## Contents -- [Users and roles created by epiphany](#users-and-roles-created-by-epiphany) - +- [Users and roles created by Epiphany](#users-and-roles-created-by-epiphany) +- [Ports used by components in Epiphany](#ports-used-by-components-in-epiphany) ### Users and roles created by epiphany @@ -12,6 +12,7 @@ By default Epiphany is creating user operations that is used to connect to machi be changed in Epiphany yaml configuration files. Additional to users created by each component Epiphany creates also users and groups: + - haproxy_exporter/haproxy_exporter - kafka_exporter/kafka_exporter - node_exporter/node_exporter @@ -20,4 +21,69 @@ Additional to users created by each component Epiphany creates also users and gr - rabbitmq/rabbitmq - zookeeper/zookeeper - kafka/kafka + +Other accounts created by each component you can find in these components documentation. + + +### Ports used by components in Epiphany + +Below you can find list of ports used by default in Epiphany on per component basis. Some of them can be changed to +different values. + +1. OS services: + + - 22 - ssh + +2. Prometheus exporters: + + - 9100 - Node exporter + - 9101 - HAProxy exporter + - 9308 - Kafka exporter + +3. Zookeeper: + + - 2181 - Zookeeper client + - 2888 - Zookeeper nodes + - 3888 - Zookeper inter nodes + +4. Kafka: + + - 9092 - Kafka broker + +5. Elasticsearch: + + - 9200 - Elasticsearch REST communication + - 9300 - Elasticsearch nodes communication + +6. Kibana: + + - 5601 - Kibana web UI + +7. Prometheus: + + - 9090 - Prometheus server + +8. Alertmanager: + + - 9093 - Alertmanager service + +9. Grafana: + + - 3000 - Grafana web UI + +10. RabbitMQ: + + - 5672 - RabbitMQ server + +11. Postgresql: + + - 5432 - Postgresql server + +12. Kubernetes: + - 4149 - kubelet + - 6443 - kube-apiserver + - 9099 - calico-felix + - 10250 - kubelet + - 10255 - kubelet + - 10256 - kube-proxy From c87c3f91f2f9f97aa250b7f63847f1005e62e370 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Tue, 6 Aug 2019 16:29:09 +0200 Subject: [PATCH 10/57] Item: #422 Desc: Add missing ports for prometheus and grafana (#425) --- .../infrastructure/virtual-machine.yml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 360c58af7d..5c7aa2787c 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -452,6 +452,26 @@ specification: destination_port_range: "9100" source_address_prefix: "10.1.0.0/20" destination_address_prefix: "0.0.0.0/0" + - name: prometheus + description: Allow connection to Prometheus + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9090" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: grafana + description: Allow connection to Grafana + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "3000" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 From 19c3d7dff70346dce2ebbb146a0c79680b2f6b84 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Wed, 7 Aug 2019 11:05:55 +0200 Subject: [PATCH 11/57] Feature/skip terraform if any (#426) * Item: #422 Desc: Add missing ports for prometheus and grafana * Item: #424 Desc: Automatically pass infrastructure creation when provider is any --- core/src/epicli/cli/engine/EpiphanyEngine.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/epicli/cli/engine/EpiphanyEngine.py b/core/src/epicli/cli/engine/EpiphanyEngine.py index 160ac4210c..fe2f3e5266 100644 --- a/core/src/epicli/cli/engine/EpiphanyEngine.py +++ b/core/src/epicli/cli/engine/EpiphanyEngine.py @@ -97,7 +97,7 @@ def apply(self): self.process_infrastructure_docs() - if not self.skip_infrastructure: + if not (self.skip_infrastructure or self.is_provider_any(self.cluster_model)): # Generate terraform templates with TerraformTemplateGenerator(self.cluster_model, self.infrastructure_docs) as template_generator: template_generator.run() @@ -131,3 +131,6 @@ def dry_run(self): return [*self.input_docs, *self.configuration_docs] + @staticmethod + def is_provider_any(cluster_model): + return cluster_model["provider"] == "any" From 7625cfc8f74d02405dab91028d17b371a36874d8 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 7 Aug 2019 16:56:30 +0200 Subject: [PATCH 12/57] Changing latest tag to build id in Dockerfiles (#428) --- core/core/src/docker/test-CI/Dockerfile | 4 +++- core/src/epicli/tests/docker/test-ci-epicli/Dockerfile | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/core/src/docker/test-CI/Dockerfile b/core/core/src/docker/test-CI/Dockerfile index 7c69c606b6..d04fe89112 100644 --- a/core/core/src/docker/test-CI/Dockerfile +++ b/core/core/src/docker/test-CI/Dockerfile @@ -1,4 +1,6 @@ -FROM epiphanyregistry.azurecr.io/epiphany-deploy:latest +ARG BUILD_ID + +FROM epiphanyregistry.azurecr.io/epiphany-deploy:$BUILD_ID RUN mkdir /tmp/keys diff --git a/core/src/epicli/tests/docker/test-ci-epicli/Dockerfile b/core/src/epicli/tests/docker/test-ci-epicli/Dockerfile index 5cdc3c6100..55ba918de3 100644 --- a/core/src/epicli/tests/docker/test-ci-epicli/Dockerfile +++ b/core/src/epicli/tests/docker/test-ci-epicli/Dockerfile @@ -1,4 +1,6 @@ -FROM epiphanyregistry.azurecr.io/epicli:latest +ARG BUILD_ID + +FROM epiphanyregistry.azurecr.io/epicli:$BUILD_ID RUN mkdir /tmp/keys From 3501e73f63109ad0297da27c38ba77aaf965a3c1 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Thu, 8 Aug 2019 13:16:51 +0200 Subject: [PATCH 13/57] Setup Diffie-Hellman settings in haproxy. (#430) * Item: #422 Desc: Add missing ports for prometheus and grafana * Item: #429 Desc: Add Diffie-Hellman settings to haproxy --- .../common/ansible/playbooks/roles/haproxy/files/dhparam | 8 ++++++++ .../ansible/playbooks/roles/haproxy/tasks/Debian.yml | 5 +++++ .../ansible/playbooks/roles/haproxy/tasks/RedHat.yml | 4 ++++ .../roles/haproxy/templates/haproxy_Debian.cfg.j2 | 2 ++ .../roles/haproxy/templates/haproxy_RedHat.cfg.j2 | 2 ++ 5 files changed, 21 insertions(+) create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/haproxy/files/dhparam diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/files/dhparam b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/files/dhparam new file mode 100644 index 0000000000..088f9673dc --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/files/dhparam @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/Debian.yml index 52becd2059..fb383e8dd7 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/Debian.yml @@ -80,6 +80,11 @@ dest: /etc/haproxy/haproxy.cfg src: haproxy_{{ ansible_os_family }}.cfg.j2 +- name: Copy dhparam config + copy: + dest: /etc/haproxy/dhparam + src: "dhparam" + - name: Copy haproxy rsyslog config copy: dest: /etc/rsyslog.d/haproxy.conf diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml index a60f103caa..8cc4fe36bc 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml @@ -107,6 +107,10 @@ dest: /etc/opt/rh/rh-haproxy18/haproxy/haproxy.cfg src: "haproxy_{{ ansible_os_family }}.cfg.j2" +- name: Copy dhparam.pem config + copy: + dest: /etc/opt/rh/rh-haproxy18/haproxy/dhparam + src: "dhparam" - name: Uncomment modules loading replace: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_Debian.cfg.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_Debian.cfg.j2 index 96631b0ba5..be0d06182d 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_Debian.cfg.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_Debian.cfg.j2 @@ -17,6 +17,8 @@ global ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + ssl-dh-param-file /etc/haproxy/dhparam + defaults log global diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_RedHat.cfg.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_RedHat.cfg.j2 index a69cd23c70..90567af333 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_RedHat.cfg.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/templates/haproxy_RedHat.cfg.j2 @@ -17,6 +17,8 @@ global ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets + ssl-dh-param-file /etc/opt/rh/rh-haproxy18/haproxy/dhparam + defaults log global From ef96749dbab9fa1ea67dadbaa3e49979f16e009b Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Thu, 8 Aug 2019 15:26:04 +0200 Subject: [PATCH 14/57] AzureCLI integration (#427) * - Added login to Azure-CLI and selection of subscription. - Added creation of service principle. - Added creation of the resource group. * - Added posibility to run without service principal * - Changed text outputs * - Fixed typo. --- core/src/epicli/Pipfile | 1 + core/src/epicli/Pipfile.lock | 1280 ++++++++++++++++- core/src/epicli/cli/engine/EpiphanyEngine.py | 2 +- .../src/epicli/cli/engine/TerraformCommand.py | 28 +- core/src/epicli/cli/engine/TerraformRunner.py | 36 +- core/src/epicli/cli/engine/azure/APIProxy.py | 3 +- .../epicli/cli/engine/azure/AzureCommand.py | 49 + .../cli/engine/azure/InfrastructureBuilder.py | 9 +- core/src/epicli/cli/helpers/build_saver.py | 11 +- core/src/epicli/cli/helpers/data_loader.py | 9 +- .../data/azure/terraform/epiphany-cluster.j2 | 20 +- .../data/common/defaults/epiphany-cluster.yml | 2 + 12 files changed, 1400 insertions(+), 50 deletions(-) create mode 100644 core/src/epicli/cli/engine/azure/AzureCommand.py diff --git a/core/src/epicli/Pipfile b/core/src/epicli/Pipfile index 71b04fb11d..ed5f207f30 100644 --- a/core/src/epicli/Pipfile +++ b/core/src/epicli/Pipfile @@ -17,6 +17,7 @@ jsonschema = "*" python-json-logger = "*" ansible = "*" terraform-bin = "*" +azure-cli = "==2.0.67" [requires] python_version = "3.7" diff --git a/core/src/epicli/Pipfile.lock b/core/src/epicli/Pipfile.lock index 8e4dcaa976..145e40a02b 100644 --- a/core/src/epicli/Pipfile.lock +++ b/core/src/epicli/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b528cc683e3bdc332aae79a02b9a941f936cb790e13580d677495f989d693128" + "sha256": "72adf6714817ddb52447f1fdaeedbd9562305bd3ace6d71d4af90bdc0c43aff4" }, "pipfile-spec": 6, "requires": { @@ -16,41 +16,1019 @@ ] }, "default": { + "adal": { + "hashes": [ + "sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf", + "sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1" + ], + "version": "==1.2.2" + }, "ansible": { "hashes": [ - "sha256:05f9ed3ca3e06dffaa87a73a8e6f7f322825bc3f609f8b71c4fe22dbbdf72abc" + "sha256:05f9ed3ca3e06dffaa87a73a8e6f7f322825bc3f609f8b71c4fe22dbbdf72abc" + ], + "index": "pypi", + "version": "==2.8.3" + }, + "antlr4-python3-runtime": { + "hashes": [ + "sha256:168cdcec8fb9152e84a87ca6fd261b3d54c8f6358f42ab3b813b14a7193bb50b" + ], + "markers": "python_version >= '3.0'", + "version": "==4.7.2" + }, + "applicationinsights": { + "hashes": [ + "sha256:42a2eb05fad51ffdd8246fdf5b2d2c0166d2b34f75a06940a2443d7e17a219fe", + "sha256:c4712ede8eeca57e611b7fd4b3b6c345745a4a002a08145ab45f92d31d900040" + ], + "version": "==0.11.7" + }, + "argcomplete": { + "hashes": [ + "sha256:2f2052ea5156eb5cc7edce9c0ddc937e30c49c1097d51b24f34350a08632a264", + "sha256:45836de8cc63d2f6e06b898cef1e4ce1e9907d246ec77ac8e64f23f153d6bec1" + ], + "version": "==1.10.0" + }, + "asn1crypto": { + "hashes": [ + "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", + "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" + ], + "version": "==0.24.0" + }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, + "azure-batch": { + "hashes": [ + "sha256:38a1a20a25a04c26f5bbe65f47e0c456d87ec4b6109bad2c97e10de9f48ecb38", + "sha256:d89aaa65947c80541939c16e284adaef6d0af3c52cadb7b82af94d062ad88cf3" + ], + "version": "==6.0.0" + }, + "azure-cli": { + "hashes": [ + "sha256:4c7e87f8bb6f6143f5a2c2bc9c2e7e7d56f6836dbb658cca00452cfd09194ec5", + "sha256:b1aa8fb64ed8a1c342ae9f1351b71a25c718ee9be8ae8f05d47f5eb18abadf32" + ], + "index": "pypi", + "version": "==2.0.67" + }, + "azure-cli-acr": { + "hashes": [ + "sha256:05d22a3c52b264eb291d7ce54c69813d001f7e5507ce5cd95b4b49e4ad76b0f3", + "sha256:577d35fc11dad396bfb4983e9cd210b9da73623c7e51490f8274fa938646910e" + ], + "version": "==2.2.9" + }, + "azure-cli-acs": { + "hashes": [ + "sha256:d06cb69f644d81d7fb077fe9de3aefc8f36f0da5463f245dcb385c72a34269fa", + "sha256:f89fbca9ae4d070be8924eac6ed7bdf44a64a4850d825330bc6f0daecf946e86" + ], + "version": "==2.4.4" + }, + "azure-cli-advisor": { + "hashes": [ + "sha256:41720839c2cca7a6933a5f0809eb3810ba81f4d4297e97dd858499932309d83a", + "sha256:63bdd1d8fa356c6b05f8a8681e48b02f11e667548ffc9d1c7cd16712796ff1bd" + ], + "version": "==2.0.1" + }, + "azure-cli-ams": { + "hashes": [ + "sha256:e0891607580002e3e036b793ebfa7c214b2b6b3dc638d1aa65eec25a4906950d", + "sha256:eb4f56604abd26c29e30f525ae32f291255f3bd2eb82a4f5dc70f7ff9f833583" + ], + "version": "==0.4.7" + }, + "azure-cli-appservice": { + "hashes": [ + "sha256:62afd6263410eefa4fc07e50318fdb11bb82dc6cb6d16412403d3b4bf15a3fcf", + "sha256:76460184083e5a4dcb38c02ed8c2cc3e180c8396df135cf3b1e27c4214e8df06" + ], + "version": "==0.2.21" + }, + "azure-cli-backup": { + "hashes": [ + "sha256:a16561644880745f349cfbaaeba2fb634586d4277e63dd42f613fa525263c526", + "sha256:e2adf1f830cc38a16b099ab168e3029835e81f1880d76fbee0fd52c890aaa3c2" + ], + "version": "==1.2.5" + }, + "azure-cli-batch": { + "hashes": [ + "sha256:2fd21a7bf6974b920c010da3b57f927988d0662daf9cfdab0ec2e0fb00ec39df", + "sha256:58eae1d7ccdbd20abe9650e0cac42e596389d7540dc11e9c07e87004d8c96135" + ], + "version": "==4.0.3" + }, + "azure-cli-batchai": { + "hashes": [ + "sha256:83dea6ab0d7dea8ec258c6983996a24f2fc7039d71a636a7efc0845cd2dbf1b6", + "sha256:c93123902f5a5da7ac455ae11abb6c008b73eb8b784c7955564202a6b021422c" + ], + "version": "==0.4.10" + }, + "azure-cli-billing": { + "hashes": [ + "sha256:31433a8ab55828683297996fad99ced4f6891431557e9c081cd424b866154197", + "sha256:dab2cd82443ff66b6aed540123fbd83f174af49e059491d78aca90cfa4c0aaba" + ], + "version": "==0.2.2" + }, + "azure-cli-botservice": { + "hashes": [ + "sha256:4d9e290a9a83a2265b7a3a24d25cc2b5752a374711987260cee4acc464d4a28f", + "sha256:6d6a801c0428b577943962924d780715122530da6d7174076b8fb4aa3e470447" + ], + "version": "==0.2.2" + }, + "azure-cli-cdn": { + "hashes": [ + "sha256:654d9f03655a1c7703cc4fa6cac31f97c476e795e567eec03d0bd1e184c02320", + "sha256:88a16b2f248eee98cc40181b2f98764f231d30cc35061f4925d34c108a36eeab" + ], + "version": "==0.2.4" + }, + "azure-cli-cloud": { + "hashes": [ + "sha256:0df0268da7978868192f2d241d3049b16f4d8badf5a0c870be73c7f366dbc6d4", + "sha256:2bb40d7e76216789e8b1c4e993f8724c8f156b41537330170c64e5f63257ac3d" + ], + "version": "==2.1.1" + }, + "azure-cli-cognitiveservices": { + "hashes": [ + "sha256:709db9aec859f0dd557f5235fae43d3bb049393b5e447d0a4c1399b51265262a", + "sha256:b0cd3298f5e44ce057bd8b2b5022e15489bf94ec145edd79ce16bc38feb9e2e5" + ], + "version": "==0.2.6" + }, + "azure-cli-command-modules-nspkg": { + "hashes": [ + "sha256:0698597ce4bf5d90e335415c271c8d025fe75dce1655c1934ac00bd16a661ca5", + "sha256:a3f85eb636e403809734b1131423518348382208a2d28a08c272160a6cce9086" + ], + "version": "==2.0.2" + }, + "azure-cli-configure": { + "hashes": [ + "sha256:0645e91c86475aceb8314e56d524e493d9b39e802845b6006900ae8160f5a172", + "sha256:85cd7f7a1cb639b57f098bb249040abaa987f3c948b34979ca630874eaf218af" + ], + "version": "==2.0.24" + }, + "azure-cli-consumption": { + "hashes": [ + "sha256:5a97ce88c0e86d1f05beb614e820e14cb8bacc913070390128a832acda678619", + "sha256:6c96763ec86acfbe6b8e3207c9ab2fb9ef08c28d33a68431e31f0fc538ccb13e" + ], + "version": "==0.4.4" + }, + "azure-cli-container": { + "hashes": [ + "sha256:0c1b46aacd9bcd24f27cf92b5b7ed6193bc1aa8b05aafde7c3bb1ea7cdf69bad", + "sha256:97108da14807227f08542b8b6a9d907942b28df34423f6be604516f3e188cb53" + ], + "version": "==0.3.18" + }, + "azure-cli-core": { + "hashes": [ + "sha256:a3f3c41dd751a30359cde904fa7ecb20a9f87ef64f8b9a4c1259156b79e99299", + "sha256:af52a0af876ca1153ff71d2d320234e681c35a8cbdcf14336edd55e57b9ab565" + ], + "version": "==2.0.67" + }, + "azure-cli-cosmosdb": { + "hashes": [ + "sha256:2b1dc92d65f8ff7fc4abc0f4e6f9ffdf46c3229f0f3ee956c339bacd2f1544a0", + "sha256:4c3cbe941a920c2331bb6a3c9116135a3e2c14255f75498392fd14111781aad5" + ], + "version": "==0.2.11" + }, + "azure-cli-deploymentmanager": { + "hashes": [ + "sha256:1d9aeddd0269560de80c11d29f948bb99505119a3e72f5368556ed0575ea614e", + "sha256:e8fa7f69b6e322bceff4ed153295ceef6a11636aaab6d995f51274f4ac63ad20" + ], + "version": "==0.1.1" + }, + "azure-cli-dla": { + "hashes": [ + "sha256:92d7708ec9ffea1d3a4e39ab51c48a8e1e61c87c9f9e002fec7fcb9a727a4a9f", + "sha256:b595642d732f55a612f75de616759c036fdb470a24f3ab3102c7e7d65d189486" + ], + "version": "==0.2.6" + }, + "azure-cli-dls": { + "hashes": [ + "sha256:2ff4769754dbb168cf234151ffa40882d1c7deb0097468ef2cf1e7c9ecc3a389", + "sha256:8789a378b71edb7d205e2c8569c9084bedce26a9dde8f7aeb4c2fd4674d78bba" + ], + "version": "==0.1.10" + }, + "azure-cli-dms": { + "hashes": [ + "sha256:a16fe2d364f5c48e6ad9a196e6f9052698fff336ac52cb43988f0d12e193e97d", + "sha256:ac6570e8da3c46709173ed8a1891e5de367074842b09432d357cee7d0371077a" + ], + "version": "==0.1.4" + }, + "azure-cli-eventgrid": { + "hashes": [ + "sha256:33b8cbcab70a7fb7f38bd4f302d700c14b8f09baae1766fa76df5bea9d0a29b7", + "sha256:62e4dd24c96539d82172f521061961f38127c59abe1287ae1a1598a246867707" + ], + "version": "==0.2.4" + }, + "azure-cli-eventhubs": { + "hashes": [ + "sha256:380c584d45da5a6a7b8daca71ea41ea22b2a599f3ddd258c278d1215a39c056f", + "sha256:6cc5670b79e426c634cf7e9a1df049523c0726645f8cca7823a8986c57b6992b" + ], + "version": "==0.3.7" + }, + "azure-cli-extension": { + "hashes": [ + "sha256:94f74bc305c78255d595ac136c46e6e375cee0126930f182d7ba02eabea21e3f", + "sha256:ebe127b90467c66a8f6035ee0e1bd053d684467d801906f6199f399a878c78b9" + ], + "version": "==0.2.5" + }, + "azure-cli-feedback": { + "hashes": [ + "sha256:09cf9538b79828f1e32b3fbc074ec0720ff4f5278f5cd2fea6ca11e64addd17f", + "sha256:73c43f4b9495465b9b1d8bc0d94e06bf4f08e2124d171b02c92b4206997a6f9e" + ], + "version": "==2.2.1" + }, + "azure-cli-find": { + "hashes": [ + "sha256:193c15f57847ac992e21c1fa05a241f9a2cac0b2fd9d8099a139cf3b4254535c", + "sha256:807a7bd4aab7f1f9e55affa396646f7faef6d6550a646599d3af7e457d2b3bd4" + ], + "version": "==0.3.4" + }, + "azure-cli-hdinsight": { + "hashes": [ + "sha256:6c8b15cad14bad6e0bbae4f7ded521c2ce25363101d942a80c654b464422fe58", + "sha256:f361829336c172261075ffb984c5eeed6914fbf92336b0b66b9a0fdf03e5dff0" + ], + "version": "==0.3.5" + }, + "azure-cli-interactive": { + "hashes": [ + "sha256:9b5c518d132ebe8ba5db1b1c4c28231be57d653de4e316fba853e1afaad6f33e", + "sha256:bf265d5ca7d0c3d9b79927b76a8bca6096facac92b733ebe27bbba8bfde1c422" + ], + "version": "==0.4.5" + }, + "azure-cli-iot": { + "hashes": [ + "sha256:33029acfe18c19f3a95245b86192d0ab630d329b0013f389e1b76e689a28f4ec", + "sha256:ad96f6ba12c352967ac2a93d830fdd02b9d0a4fc1f56d6055aa84ba116ce9866" + ], + "version": "==0.3.11" + }, + "azure-cli-iotcentral": { + "hashes": [ + "sha256:da621bdda0bd428e395d570249db1717e56465983a30cf8ff724d28fd200487f", + "sha256:f7fcc39da95d76b8ca7d67df2574308fddc498c7c5bfcc0f1464a326abcaad64" + ], + "version": "==0.1.7" + }, + "azure-cli-keyvault": { + "hashes": [ + "sha256:2d1200e354bee8a56290b3a94f1f8c54fc32b30344ba5587a9cfd973349b3ec9", + "sha256:66711e7f5d119b76aaae17c8d16ffb8801ce233ed29ff71ed6255a389dd0c880" + ], + "version": "==2.2.16" + }, + "azure-cli-kusto": { + "hashes": [ + "sha256:a52f9adae4b362a677188d9061fb032949283dbee17e7cff32a24bfdbfb853f9", + "sha256:f4262d1b9bef9f29c99f2ea8a2eea94759e06e1e33953a35dab02149b50b4dee" + ], + "version": "==0.2.3" + }, + "azure-cli-lab": { + "hashes": [ + "sha256:6c0cea9a5a643008243a47043fcc08ce69da3ff4a878e9bb2f318c011893c475", + "sha256:ab32b224fec8905c525eb7deefc444fdc84ec0e4b48dd7149378e84ce4b622cf" + ], + "version": "==0.1.8" + }, + "azure-cli-maps": { + "hashes": [ + "sha256:480cbbd0b75b2d0d4897fc340131c3818c68508386a681653c3e9c778d61763e", + "sha256:61e52d7f40e0f2162f83c324c15828b9df1d4c00d5b45aca11336262ee5163b7" + ], + "version": "==0.3.5" + }, + "azure-cli-monitor": { + "hashes": [ + "sha256:cda6ef9bbc66dbb5d645d59821c553822b56f368774e65ce8649c00ab4c8f127", + "sha256:e48590ab2c3d9f17978f1e55d556b7d56566e362746b6aff777ff75e114d89ea" + ], + "version": "==0.2.15" + }, + "azure-cli-natgateway": { + "hashes": [ + "sha256:174ce89ec0dd3e6ece12007623c01c03e2a087ade2c539507ee7d49f006528c8", + "sha256:d00862ca7263bf10a6a4a31d29eed30dd345b013ed862d0aaedb902bffd601a6" + ], + "version": "==0.1.1" + }, + "azure-cli-network": { + "hashes": [ + "sha256:86923f8afcf1fd38c074fad39f337cb26b1549233e6b002cac9f7667a7f9e423", + "sha256:acfd670c5e7e235f1678ccb8682a3d56e47d1ac00a98e2ca59f2b106296e33b1" + ], + "version": "==2.5.2" + }, + "azure-cli-nspkg": { + "hashes": [ + "sha256:1bde56090f548c6435bd3093995cf88e4c445fb040604df8b5b5f70780d79181", + "sha256:9a1e4f3197183470e4afecfdd45c92320f6753555b06a70651f89972332ffaf6" + ], + "version": "==3.0.4" + }, + "azure-cli-policyinsights": { + "hashes": [ + "sha256:83dda6cbd5923c7124993a92586c3f28625f4151101b39e9e98871fc13b39750", + "sha256:ca6c3029c06176db2a549ce69428009c23415aba99431910e9483381b23a4d98" + ], + "version": "==0.1.4" + }, + "azure-cli-privatedns": { + "hashes": [ + "sha256:2a18b19d26bfa8ad4b473d46ad9b887a11a8a295074b82b0971fd9c76b8bb24c", + "sha256:634d0f7fc5ade32cc3d2b19db23a687211a1c16a52e5c19d6f5d2301413d0cf1" + ], + "version": "==1.0.2" + }, + "azure-cli-profile": { + "hashes": [ + "sha256:21966eb8ece9282845a8943bd7d99d1df69841bc8a4679b43c1780464232e7ac", + "sha256:bb65193178b7ba3c2c712d87367317c53c8dd3b2ef0f37155f0bab9f19281ebf" + ], + "version": "==2.1.5" + }, + "azure-cli-rdbms": { + "hashes": [ + "sha256:931419372a4695aa978287a9a42b028e79b5bb551baf719a86bb343f8598548c", + "sha256:f5e8a670020f9ed20fea3b2dfb5cf82d136cbf02fe5156f57fe6cc398073373d" + ], + "version": "==0.3.12" + }, + "azure-cli-redis": { + "hashes": [ + "sha256:5c3802730ef17264d9400a11f0ae731a8af02c2fb0f45d717adc036b3b882b06", + "sha256:df29cc82dc25da69a6c181f6ff4bc11a1df4e1f717bc3eabb77a58b97fa5ce35" + ], + "version": "==0.4.4" + }, + "azure-cli-relay": { + "hashes": [ + "sha256:4c48b8f83665f8c874bb77199c238e0b913897a1d8ade64477d783c0b8a4b805", + "sha256:879c4a41f84a8168082e3b65f26081c8872b6986abf3310c8978554635ed1bab" + ], + "version": "==0.1.5" + }, + "azure-cli-reservations": { + "hashes": [ + "sha256:2cb8e8e8e39c18d5d537118fb13bfae3f2321c51e96a4ca8c61066c95b3ad61f", + "sha256:8deaf25bdb1c7acb09c29be3d40c48a1f28f6e62a8f816b5173ae57a14376709" + ], + "version": "==0.4.3" + }, + "azure-cli-resource": { + "hashes": [ + "sha256:9433c106ede349a7806426452cfd3a0f496560f15a5959faef15e58f12fd4a2c", + "sha256:d4a5c18de5bec0ed844dda0efb6d342af7868237b8591d7aed52ef0cef811333" + ], + "version": "==2.1.16" + }, + "azure-cli-role": { + "hashes": [ + "sha256:0984af4b1bfa51566d4e518d85f1245785ae51c7374392823644a71f505481ab", + "sha256:0a561dcf8bed65257ef34ee422eb43132c25fd35b440fe1b3c42c19e3e326ef9" + ], + "version": "==2.6.4" + }, + "azure-cli-search": { + "hashes": [ + "sha256:7f6c11e380172b2b91421e8416f94d055af6a35cc70e16718325d9f04445f455", + "sha256:a9326dec182a17e69b25887627f53cce1e4d00240b3af43596fe088a94b0745e" + ], + "version": "==0.1.2" + }, + "azure-cli-security": { + "hashes": [ + "sha256:a2d859756d73dbfd81e178008307f45b3d9a7ce07d29f3be6b0ab75929904ca1", + "sha256:f6e7e0f21c54584f4a19b94339054e68c57d87a87567fbf8168066e12b04a6ef" + ], + "version": "==0.1.2" + }, + "azure-cli-servicebus": { + "hashes": [ + "sha256:86de377a1481f3a613d5de137b298ac636cc29d32aa0a0a120ac9583340f404e", + "sha256:c3311d7858548b83650cdf9f2a2e0178112e16e8d4a3062a2bf42d1789fbae81" + ], + "version": "==0.3.6" + }, + "azure-cli-servicefabric": { + "hashes": [ + "sha256:8a81b4192ad128d1dfdfae4cdd5f453e9d39d5592a7879c82752a20870901a40", + "sha256:d7c56615a13d321438ea5fd4063d463e3e0e395b6902d287d7c046844256bb28" + ], + "version": "==0.1.20" + }, + "azure-cli-signalr": { + "hashes": [ + "sha256:3b97c2d1e19341fe37942c489c3ec06bada20550342d56985539a344057c5c06", + "sha256:48722925ba3bcaa99965573cafafb22d03c842ff74ffe8e972f9daf525c77176" + ], + "version": "==1.0.1" + }, + "azure-cli-sql": { + "hashes": [ + "sha256:6da3a23d05d2d77c3ba3212509254918e18fe0e2cdbff2a66c81a65a819ac487", + "sha256:8fd8da72924b08b84f436f4ad412bcf72c170b9389cd647bceef699322847fde" + ], + "version": "==2.2.5" + }, + "azure-cli-sqlvm": { + "hashes": [ + "sha256:0bc03736268e141b9076bbd56b330283b4c71c14cb726f572f40e17cc2354d84", + "sha256:fa8d24d2eac7290c677ca7b117d93a97d15c1827f999dee255bed1053e6c8289" + ], + "version": "==0.2.0" + }, + "azure-cli-storage": { + "hashes": [ + "sha256:8feac51e6e0450962ed52681d0fa44246ac2163dd5c90d92c92c09263751fff8", + "sha256:e18ce6134d39c5a7335b60e573534e476d81df2dbae85bd15bf2cf7a7de10ae6" + ], + "version": "==2.4.3" + }, + "azure-cli-telemetry": { + "hashes": [ + "sha256:946de5b922e3183be13afe348eae6691883d6694ff43806752662e661757de4c", + "sha256:c0141ddeed1319bcc3179617f74859e5f17477ce676051a4ead1d29c75eb9593" + ], + "version": "==1.0.2" + }, + "azure-cli-vm": { + "hashes": [ + "sha256:b9727f18ff7f1bbb9155ca493e07b7d029b6446ed0433c47430fc96d0dc385b8", + "sha256:fc346cd136e6feda75373701d083f284846c35cb65ee1791998aa939b8b2e2e8" + ], + "version": "==2.2.23" + }, + "azure-common": { + "hashes": [ + "sha256:53b1195b8f20943ccc0e71a17849258f7781bc6db1c72edc7d6c055f79bd54e3", + "sha256:99ef36e74b6395329aada288764ce80504da16ecc8206cb9a72f55fb02e8b484" + ], + "version": "==1.1.23" + }, + "azure-cosmos": { + "hashes": [ + "sha256:3061e081150320a8aba5bf0204fa1c26329478bd9f00af1c1a64e0ebf53dae48", + "sha256:8021effaaa2277a83094e29f7c099eb2e927a4ca84c2aaafc6b71e827b956eef", + "sha256:f3922891baf59742556cbc8bd96aaba4f582a6a8f9bbccb8f2b0376539a21761" + ], + "version": "==3.1.1" + }, + "azure-datalake-store": { + "hashes": [ + "sha256:995703113db6840aa02abab71b2d0699dd283a12130cd843fff8c7a1acde9661", + "sha256:fd1ca3384808ac806470c26c98bc2346c1784d5b281fac4ea468ba018269ee3a" + ], + "version": "==0.0.39" + }, + "azure-functions-devops-build": { + "hashes": [ + "sha256:adc4c45de5510acf4c094df84b54bc7767e1466e4bfdce23b99ffccf29de3f2f", + "sha256:c6341abda6098813f8fa625acd1e925410a17a8a1c7aaabdf975bb7cecb14edf" + ], + "version": "==0.0.22" + }, + "azure-graphrbac": { + "hashes": [ + "sha256:0b266602dfc631dca13960cc64bac172bf9dea2cccbb1aa13d1631ce76f14d79", + "sha256:d0bb62d8bf8e196b903f3971ba4afa448e4fe14e8394ebfcdd941d84d62ecafe" + ], + "version": "==0.60.0" + }, + "azure-keyvault": { + "hashes": [ + "sha256:37a8e5f376eb5a304fcd066d414b5d93b987e68f9212b0c41efa37d429aadd49", + "sha256:dec5334cde846849dfe7896f2e98f17b4f4d75c316a4d30e7171ce71ca20713d" + ], + "version": "==1.1.0" + }, + "azure-mgmt-advisor": { + "hashes": [ + "sha256:1929d6d5ba49d055fdc806e981b93cf75ea42ba35f78222aaf42d8dcf29d4ef3", + "sha256:9e424188d71cd35478bff4591eeee2ceb0b097da87f349bc5de5b39799be26de" + ], + "version": "==2.0.1" + }, + "azure-mgmt-applicationinsights": { + "hashes": [ + "sha256:929c30559692c77d424ca36f11e98f066c98e7eb7b742c44beadc082715f19df", + "sha256:f10229eb9e3e9d0ad20188b8d14d67055e86f3815b43b75eedf96b654bee2a9b" + ], + "version": "==0.1.1" + }, + "azure-mgmt-authorization": { + "hashes": [ + "sha256:2b8504763ea8b1b475f2c3533b171bedb91ffae459f48f1f885ec8536df91093", + "sha256:535de12ff4f628b62b939ae17cc6186226d7783bf02f242cdd3512ee03a6a40e" + ], + "version": "==0.50.0" + }, + "azure-mgmt-batch": { + "hashes": [ + "sha256:a731e6269073690f65ada0e38de75ce07f48fbf17dcd7c59d98dc901882e81b7", + "sha256:dc929d2a0a65804c28a75dc00bb84ba581f805582a09238f4e7faacb15f8a2a3" + ], + "version": "==6.0.0" + }, + "azure-mgmt-batchai": { + "hashes": [ + "sha256:b5f7df6a77fde0bd6b486762eb2c81750b6f1730ee1116689d2dfbd3e03dba95", + "sha256:f1870b0f97d5001cdb66208e5a236c9717a0ed18b34dbfdb238a828f3ca2a683" + ], + "version": "==2.0.0" + }, + "azure-mgmt-billing": { + "hashes": [ + "sha256:3810cdda69ec1409191b292628fe6ba86ce5e0444723b960d91af4f401846ac3", + "sha256:85f73bb3808a7d0d2543307e8f41e5b90a170ad6eeedd54fe7fcaac61b5b22d2" + ], + "version": "==0.2.0" + }, + "azure-mgmt-botservice": { + "hashes": [ + "sha256:375584c849ca4a21ff6d9b5621b69b249bbdb9470560dcd77820f8daf3ff2fb1", + "sha256:b21d8858e69aa16d25b908c40116a1f773c127ec4dd602cbb8542ebf39a55d83" + ], + "version": "==0.2.0" + }, + "azure-mgmt-cdn": { + "hashes": [ + "sha256:0cdbe0914aec544884ef681e31950efa548d9bec6d6dc354e00c3dbdab9e76e3", + "sha256:d80bfcbc342fa118d618c80ee2f3e163a2fa41d184f1d70a826020920dbc8a39" + ], + "version": "==3.1.0" + }, + "azure-mgmt-cognitiveservices": { + "hashes": [ + "sha256:36b406ee4b6652cd144a99309cd823ac1c726b0160120c14e4c35cb668f3f8ff", + "sha256:c3247f2786b996a5f328ebdaf65d31507571979e004de7a5ed0ff280f95d80b4" + ], + "version": "==3.0.0" + }, + "azure-mgmt-compute": { + "hashes": [ + "sha256:7b297cc6aee5f51565a03652f4810a0de0ac40f1f49e32aaada107f7cf0d0d9c", + "sha256:bc200f100da77c0c910cc9e4db103d4c3f9e052222aa400630b608e410bbbefd" + ], + "version": "==5.0.0" + }, + "azure-mgmt-consumption": { + "hashes": [ + "sha256:36ea28bb2ed4bec7e4d643444085ba4debed20a01fbd87f599896a4bda3318bd", + "sha256:9a85a89f30f224d261749be20b4616a0eb8948586f7f0f20573b8ea32f265189" + ], + "version": "==2.0.0" + }, + "azure-mgmt-containerinstance": { + "hashes": [ + "sha256:274a9def808407fafe123aa8e9bc1c838a48af2de56419598db7a8b8901086e3", + "sha256:f1ea7d150447f0d8d670b7db13bd2f47320385526021053445d15c427cba6713" + ], + "version": "==1.4.0" + }, + "azure-mgmt-containerregistry": { + "hashes": [ + "sha256:7de7c542e29b441f3858447694c4e5ab933eeef74bce2dd5bdab32b6d521ecd3", + "sha256:b24be1050d54f3158e8be7f6ad677f0c8888dddefd09fb8391ebfc73d40173a4" + ], + "version": "==2.8.0" + }, + "azure-mgmt-containerservice": { + "hashes": [ + "sha256:404de5222de3f2373775619385021c77067b3fc363a89b55070cd6c557c12899", + "sha256:f5f5ded004fbd2c9820a1c5baf9225c7b55cc86689328f9a8e5abab1caba5ab0" + ], + "version": "==5.2.0" + }, + "azure-mgmt-cosmosdb": { + "hashes": [ + "sha256:0ad7e4e7b5a00be51311e92d8d1cb11ca89994c5b710e4d8353e489994d35928", + "sha256:69656c50f06263e77bf1fffc5bb6ed8dc816ba598590fd36f4549f2d0c9cc013" + ], + "version": "==0.6.1" + }, + "azure-mgmt-datalake-analytics": { + "hashes": [ + "sha256:4c7960d094f5847d9a456c18b8a3c8e60c428e3080a3905f1c943d81ba6351a4", + "sha256:4d02630f495c4b269d9512a9b214fa17c2400200cca1bdc5bcbc9dd9832956d8" + ], + "version": "==0.2.1" + }, + "azure-mgmt-datalake-nspkg": { + "hashes": [ + "sha256:2ac6fa13c55b87112199c5fb03a3098cefebed5f44ac34ab3d39b399951b22c4", + "sha256:3b9e2843f5d0fd6015bba13040dfc2f5fe9bc7b02c9d91dd578e8fe852d1b2dd", + "sha256:deb192ba422f8b3ec272ce4e88736796f216f28ea5b03f28331d784b7a3f4880" + ], + "version": "==3.0.1" + }, + "azure-mgmt-datalake-store": { + "hashes": [ + "sha256:2af98236cd7eaa439b239bf761338c866996ce82e9c129b204e8851e5dc095dd", + "sha256:9376d35495661d19f8acc5604f67b0bc59493b1835bbc480f9a1952f90017a4c" + ], + "version": "==0.5.0" + }, + "azure-mgmt-datamigration": { + "hashes": [ + "sha256:b58c5b8d2ab92b9f8660dc4a0c2ae74a6415c7b0d01732b0bcc1872323f0be3c", + "sha256:e754928992743f54d999800a5e0679ee3e91d804d23a25f12c2e6f2f86cd05df" + ], + "version": "==0.1.0" + }, + "azure-mgmt-deploymentmanager": { + "hashes": [ + "sha256:398a6d38b658c4a790e1a6884921eb98a22a10d906340bb8c9fb3207d709703f", + "sha256:802829716d956a4901440178f4024c9d08e7acc6512f247fa074fe185d3225b1" + ], + "version": "==0.1.0" + }, + "azure-mgmt-devtestlabs": { + "hashes": [ + "sha256:7e91bb139b59cfaf1c1b2b0e3e21f091768c658c1879797757dedc6312f00c8c", + "sha256:d416a6d0883b0d33a63c524db6455ee90a01a72a9d8757653e446bf4d3f69796" + ], + "version": "==2.2.0" + }, + "azure-mgmt-dns": { + "hashes": [ + "sha256:3730b1b3f545a5aa43c0fff07418b362a789eb7d81286e2bed90ffef88bfa5d0", + "sha256:5b80546b0f182d7abe90c43025cd5ca7e6605224b4d5b872cca2456667f172ef" + ], + "version": "==2.1.0" + }, + "azure-mgmt-eventgrid": { + "hashes": [ + "sha256:c62058923ed20db35b04491cd1ad6a692f337244d05c377ecc14a53c06651cc3", + "sha256:e370cb7402206ba6f5cb611130835ecf6d4ca52c647766afdfae9e928dfea7e0" + ], + "version": "==2.2.0" + }, + "azure-mgmt-eventhub": { + "hashes": [ + "sha256:e86b20aa1f6f9c77a83d4af6e708823cc3593658bcea7b12228efc48e214d7da", + "sha256:e9e8f219251e8296d17f14090488376adcdbab1ca8ffc3664b70c73015f368ff" + ], + "version": "==2.6.0" + }, + "azure-mgmt-hdinsight": { + "hashes": [ + "sha256:dd448b611744a60563b218221397747a48feff9fbc73f4e0c7b892e7146d2361", + "sha256:e86acc86539afe768a07405fa818ee9566db22b1c1e84514180aaca06bd37ec2" + ], + "version": "==0.2.1" + }, + "azure-mgmt-imagebuilder": { + "hashes": [ + "sha256:03fff1e6afd7be0dc00f4f4b9ba8325ede15ad1d1fb74804e3b031bbf6eb67d1", + "sha256:7e5efd9f641764884cbb6e1521c8e7ff67c5ff85ed367ebe8623dbd289df9457" + ], + "version": "==0.2.1" + }, + "azure-mgmt-iotcentral": { + "hashes": [ + "sha256:9aac88ed1f993965015f4e9986931fc08798e09d7b864928681a7cebff053de8", + "sha256:e247b1ba635b5d944ec0d17054353762eed2383c4852a2d207ca0fec2e10d357" + ], + "version": "==1.0.0" + }, + "azure-mgmt-iothub": { + "hashes": [ + "sha256:388be0ed9f7ec8e7e450c7677aa4f823773a99df78ecac9ae4d36653420b7c70", + "sha256:45282a992370f5eacec5350636b7aa77507e5348ebdbbbcc98c32e1e357816b2" ], - "index": "pypi", - "version": "==2.8.3" + "version": "==0.8.2" }, - "asn1crypto": { + "azure-mgmt-iothubprovisioningservices": { "hashes": [ - "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", - "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" + "sha256:2b3480a8ad2e535928da55de92b6127d02171768fed375b112274eb1e55268c1", + "sha256:8c37acfd1c33aba845f2e0302ef7266cad31cba503cc990a48684659acb7b91d" ], - "version": "==0.24.0" + "version": "==0.2.0" }, - "attrs": { + "azure-mgmt-keyvault": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:05a15327a922441d2ba32add50a35c7f1b9225727cbdd3eeb98bc656e4684099", + "sha256:406298b6236abf9e3bae3218df2fc89c25aee471b917eca7769ff5696fc8ec01" ], - "version": "==19.1.0" + "version": "==1.1.0" + }, + "azure-mgmt-kusto": { + "hashes": [ + "sha256:57a6a1a9fd0be60e5d5ff7d00bae4e9dd645308dab277b6712786aae22b5e435", + "sha256:9eb8b7781fd4410ee9e207cd0c3983baf9e58414b5b4a18849d09856e36bacde" + ], + "version": "==0.3.0" + }, + "azure-mgmt-loganalytics": { + "hashes": [ + "sha256:c7315ff0ee4d618fb38dca68548ef4023a7a20ce00efe27eb2105a5426237d86", + "sha256:f224b7d52f4369ce057c7f83e80da1d00a8887ad5c15606529e9c930e601088f" + ], + "version": "==0.2.0" + }, + "azure-mgmt-managementgroups": { + "hashes": [ + "sha256:005e8289c2e1d8a8368c96790edf6a34e5c37b4096bce2eb8a923c6d5dc11fb2", + "sha256:ff62d982edda634a36160cb1d15a367a9572a5acb419e5e7ad371e8c83bd47c7" + ], + "version": "==0.1.0" + }, + "azure-mgmt-maps": { + "hashes": [ + "sha256:a779b1ddbbcd95393e53f11b586dd26c42a709aaa226412a2df64d0da6807a80", + "sha256:c120e210bb61768da29de24d28b82f8d42ae24e52396eb6569b499709e22f006" + ], + "version": "==0.1.0" + }, + "azure-mgmt-marketplaceordering": { + "hashes": [ + "sha256:6da12425cbab0cc62f246e7266b4d67aff6bdd031ecbe50c7542c2f2b2440ad4", + "sha256:fb7a21f4a4a4b8d32bae600614f047a17993111374c9567ac11f241ada61d69f" + ], + "version": "==0.1.0" + }, + "azure-mgmt-media": { + "hashes": [ + "sha256:5d0c6b3a0f882dde8ae3d42467f03ea6c4e3f62613936087d54c67e6f504939b", + "sha256:7c270edaa22c2d2f453d7eb05c55069020c89261d813210575991d5c872c8b19" + ], + "version": "==1.1.1" + }, + "azure-mgmt-monitor": { + "hashes": [ + "sha256:838867a150694837e9c6141760ff0f20fe9e5b7ab88f9ba868fde1810855895e", + "sha256:f1a58d483e3292ba4f7bbf3104573130c9265d6c9262e26b60cbfa950b5601e4" + ], + "version": "==0.5.2" + }, + "azure-mgmt-msi": { + "hashes": [ + "sha256:8622bc9a164169a0113728ebe7fd43a88189708ce6e10d4507247d6907987167", + "sha256:e989e61753bf4eca0e688526b7c31c9a88082080acfb038fad17dda7f084a026" + ], + "version": "==0.2.0" + }, + "azure-mgmt-network": { + "hashes": [ + "sha256:611373b2ae1aae29ef2f5b745c76939c9c3760e9a4f1212612667de6ab4a74e3", + "sha256:7b7f4759c367da33be631e63320daa6663575d092c04891fef531dff6f4be516" + ], + "version": "==3.0.0" + }, + "azure-mgmt-nspkg": { + "hashes": [ + "sha256:1c6f5134de78c8907e8b73a8ceaaf1f336a24193a543039994fe002bb5f7f39f", + "sha256:8b2287f671529505b296005e6de9150b074344c2c7d1c805b3f053d081d58c52", + "sha256:d638ea5fda3ed323db943feb29acaa200f5d8ff092078bf8d29d4a2f8ed16999" + ], + "version": "==3.0.2" + }, + "azure-mgmt-policyinsights": { + "hashes": [ + "sha256:b27f5ac367b69e225ab02fa2d1ea20cbbfe948ff43b0af4698cd8cbde0063908", + "sha256:f2df831b61c6dcc36e0aa9403db44b92edf70234c0f685c4d82cdc01962d35cb" + ], + "version": "==0.3.1" + }, + "azure-mgmt-privatedns": { + "hashes": [ + "sha256:aeea39403333b280ceb7086cda6ea98ba78472735c1a14388e16d22ea87974c7", + "sha256:d29cfd8cec806e06673d9382d3f5766fc65d9a9de75b424705094a34a7db8d23" + ], + "version": "==0.1.0" + }, + "azure-mgmt-rdbms": { + "hashes": [ + "sha256:40abbe4f9c59d7906594ceed067d0e7d09fef44be0d16aded5d5717f1a8aa5ea", + "sha256:e97816a676d8039a4ca4b123fa2b3fad22991b260332aa0d27086e50ad8ad1e9" + ], + "version": "==1.8.0" + }, + "azure-mgmt-recoveryservices": { + "hashes": [ + "sha256:321d104e34a539ebc31a0890d088dce78842e6f513419517a7ce5218a42ad1bf", + "sha256:a84b6df4d2a6e07e43d1de856e8153d5e1178b92dd0c588487c67f7099a75a22" + ], + "version": "==0.1.1" + }, + "azure-mgmt-recoveryservicesbackup": { + "hashes": [ + "sha256:6a089e98ac3f1d3593a14daff116fafbcc78e2d8f65eac0ad4efb8eeaa156db1", + "sha256:76720ddfe9b2dc9259a1ab424d9e157cc7621efdf33b471f0f03708f31c21d16" + ], + "version": "==0.1.2" + }, + "azure-mgmt-redis": { + "hashes": [ + "sha256:756fd080868fd057fdaa4b7663985d8ffebd941ad06a4d9786fe4470e65a2114", + "sha256:db999e104edeee3a13a8ceb1881e15196fe03a02635e0e20855eb52c1e2ecca1" + ], + "version": "==6.0.0" + }, + "azure-mgmt-relay": { + "hashes": [ + "sha256:1411e734573ce6166ac7a75fbfc0afb7d6b3f47a94d0b4999b6adf2709eba87c", + "sha256:d9f987cf2998b8a354f331b2a71082c049193f1e1cd345812e14b9b821365acb" + ], + "version": "==0.1.0" + }, + "azure-mgmt-reservations": { + "hashes": [ + "sha256:b25dac18466204643d9450b1cb0163161254c0f7ea76136af9c6589e89c8de49", + "sha256:c86343806a539e1fa617dda0c0aab3bd039d57a421f5a3d9f9fc06816cca6a02" + ], + "version": "==0.3.1" + }, + "azure-mgmt-resource": { + "hashes": [ + "sha256:56c7d4e8d6854212977477272c600ab1d2c535de2a86095b56e948b06eb6d539", + "sha256:aef8573066026db04ed3e7c5e727904e42f6462b6421c2e8a3646e4c4f8128be" + ], + "version": "==2.1.0" + }, + "azure-mgmt-search": { + "hashes": [ + "sha256:0ec5de861bd786bcb8691322feed6e6caa8d2f0806a50dc0ca5d640591926893", + "sha256:fdbaa1721b045a4ea4a21c84c6bc1f9636b39e93dff09ffd68f22e5da88bd3ea" + ], + "version": "==2.0.0" + }, + "azure-mgmt-security": { + "hashes": [ + "sha256:1d42ced0690d10ebe5f83bf20be835e1a424d81463e59857cc402f218e3164b1", + "sha256:b1d8b9a4be33099cc05ce59035115adace79c8d5aa5ff5a516476a161064268f" + ], + "version": "==0.1.0" + }, + "azure-mgmt-servicebus": { + "hashes": [ + "sha256:bfa726ffd5ba99ef4985dd8bcc6f8f1ff42a321ad67811914be23e92631a4c5f", + "sha256:f20920b8fb119ef4abeda4d2dac765a4fc48cd0bcf30c27f8c4cc6d890bc08b1" + ], + "version": "==0.6.0" + }, + "azure-mgmt-servicefabric": { + "hashes": [ + "sha256:0c1434e789d0c036c613855b898a385a4533656f45eafae3ef7af3ecf4d6a3e8", + "sha256:b2bf2279b8ff8450c35e78e226231655021482fdbda27db09975ebfc983398ad" + ], + "version": "==0.2.0" + }, + "azure-mgmt-signalr": { + "hashes": [ + "sha256:37a79dfe21af4addbd9cdf248a260387caabdfdd60d2ba6f3174d28e96660655", + "sha256:8a6266a59a5c69102e274806ccad3ac74b06fd2c226e16426bbe248fc2174903" + ], + "version": "==0.1.1" + }, + "azure-mgmt-sql": { + "hashes": [ + "sha256:70cc423b42317041daaffb8f9df2ce3c9591ba8639fa4901a4ec8cfde5eeb1dc", + "sha256:8399702e9d1836f3b040ce0c93d8dc089767d66edb9224a3b8a6c9ab7e8ff01f" + ], + "version": "==0.12.0" + }, + "azure-mgmt-sqlvirtualmachine": { + "hashes": [ + "sha256:8afc042ef7e82f41437e1761a4627ae842618e2ea05cdccf0fcaf1089aa9e098", + "sha256:8de993db9b0bdd964cdeefc68b99b5ab9e95109c0aacb3b65d574a5efae0b63e" + ], + "version": "==0.3.0" + }, + "azure-mgmt-storage": { + "hashes": [ + "sha256:06faa7033a17ecd5127cab476a7cd79d5fe7b68e332c8e8e8303a20c9157cecd", + "sha256:4242afd6d854ea7c6170768a6072ff5057beeba481d38ee0ff316d1252849dbd" + ], + "version": "==3.3.0" + }, + "azure-mgmt-trafficmanager": { + "hashes": [ + "sha256:672f909459e70d41eb8d7bc619839cd60eb2cea2fd20dc7924b7e9670ea8aedf", + "sha256:fc8ae77022cfe52fda4379a2f31e0b857574d536e41291a7b569b5c0f4104186" + ], + "version": "==0.51.0" + }, + "azure-mgmt-web": { + "hashes": [ + "sha256:b6ddc3020cd44d1cc64331c9f4fe71478c83a5c911e3a3cf67be70a55204e46e", + "sha256:cd9997a4c5303aaec6d8366739602fa73ef308992bfdc09f5d923afa3635c194" + ], + "version": "==0.42.0" + }, + "azure-multiapi-storage": { + "hashes": [ + "sha256:3cdea71973562fffd2c3b47743b04d757dae7a47a2eb59b0b294b862ab5fd839", + "sha256:ab3dbf0c422e53161b5ba0b2e8be5f4a144d15a5c082cfa1f2ef6b7e83b7a414" + ], + "version": "==0.2.3" + }, + "azure-nspkg": { + "hashes": [ + "sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8", + "sha256:31a060caca00ed1ebd369fc7fe01a56768c927e404ebc92268f4d9d636435e28", + "sha256:e7d3cea6af63e667d87ba1ca4f8cd7cb4dfca678e4c55fc1cedb320760e39dd0" + ], + "version": "==3.0.2" + }, + "azure-storage-blob": { + "hashes": [ + "sha256:308058abfd789f5830d91f6407eb00a7b04925b2b9af267aecfb46c335802cdc", + "sha256:8cab5420ba6646ead09fdb497646f735b12645cba8efed96a86f7b370e175ade" + ], + "version": "==1.3.1" + }, + "azure-storage-common": { + "hashes": [ + "sha256:4ec87c7537d457ec95252e0e46477e2c1ccf33774ffefd05d8544682cb0ae401", + "sha256:de4817cce35a23d1c89563edc38b481ebd8da4655bdf32d26fa2b06095179e4a" + ], + "version": "==1.4.2" + }, + "azure-storage-nspkg": { + "hashes": [ + "sha256:6f3bbe8652d5f542767d8433e7f96b8df7f518774055ac7c92ed7ca85f653811", + "sha256:7da3bd6c73b8c464a57f53ae9af8328490d2267c66430d8a7621997e52a9703e" + ], + "version": "==3.1.0" + }, + "bcrypt": { + "hashes": [ + "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89", + "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42", + "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294", + "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161", + "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31", + "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5", + "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c", + "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0", + "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de", + "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e", + "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052", + "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09", + "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105", + "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133", + "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7", + "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc" + ], + "version": "==3.1.7" }, "boto3": { "hashes": [ - "sha256:0cd4a3e158f40eedb54b36b3fbe60d135db74a245f0ca8eead1af2eb6d46a649", - "sha256:68e9eba6f846cf8e01973ec565afdb1adfb9612b531c15bb5c5524394db4df5b" + "sha256:666f37c5852f71925494fc2103b189deafe6702c1d9ae60bead5b1b6466de857", + "sha256:7b77b507221ec15550b02d492804166bcc61ef3a81312968065515a76aa1791b" ], "index": "pypi", - "version": "==1.9.199" + "version": "==1.9.202" }, "botocore": { "hashes": [ - "sha256:25d87047241b7b775443570c0e790ca952f9f7491d4d6472430a4b006383a257", - "sha256:e4729c1acaa936d4c5c948a18d279f92bbf61fad9b5fb03942c753ec405e427d" + "sha256:71ca578701e746fe947c098e5dee06128d0f6ba98217ba7e29aff0dab8caf82f", + "sha256:e55003c46e71396a551d4b70f39286f8fc4094ac6cf90f5db8d7a68bb4af1f9d" + ], + "version": "==1.12.202" + }, + "certifi": { + "hashes": [ + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" ], - "version": "==1.12.199" + "version": "==2019.6.16" }, "cffi": { "hashes": [ @@ -85,6 +1063,20 @@ ], "version": "==1.12.3" }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "version": "==0.4.1" + }, "cryptography": { "hashes": [ "sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c", @@ -114,6 +1106,42 @@ ], "version": "==0.14" }, + "fabric": { + "hashes": [ + "sha256:93684ceaac92e0b78faae551297e29c48370cede12ff0f853cdebf67d4b87068", + "sha256:98538f2f3f63cf52497a8d0b24d18424ae83fe67ac7611225c72afb9e67f2cf6" + ], + "version": "==2.4.0" + }, + "humanfriendly": { + "hashes": [ + "sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d", + "sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85" + ], + "version": "==4.18" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "invoke": { + "hashes": [ + "sha256:4f4de934b15c2276caa4fbc5a3b8a61c0eb0b234f2be1780d2b793321995c2d6", + "sha256:dc492f8f17a0746e92081aec3f86ae0b4750bf41607ea2ad87e5a7b5705121b7", + "sha256:eb6f9262d4d25b40330fb21d1e99bf0f85011ccc3526980f8a3eaedd4b43892e" + ], + "version": "==1.2.0" + }, + "isodate": { + "hashes": [ + "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", + "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81" + ], + "version": "==0.6.0" + }, "jinja2": { "hashes": [ "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", @@ -137,6 +1165,13 @@ "index": "pypi", "version": "==3.0.2" }, + "knack": { + "hashes": [ + "sha256:b1ac92669641b902e1aef97138666a21b8852f65d83cbde03eb9ddebf82ce121", + "sha256:bd240163d4e2ce9fc8535f77519358da0afd6c0ca19f001c639c3160b57630a9" + ], + "version": "==0.6.3" + }, "markupsafe": { "hashes": [ "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", @@ -170,12 +1205,127 @@ ], "version": "==1.1.1" }, + "mock": { + "hashes": [ + "sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3", + "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8" + ], + "version": "==3.0.5" + }, + "msrest": { + "hashes": [ + "sha256:27589fb400da7e1a98778688f70a0099e4fc6fea59d0f4835b4fbdad3bb8a6d9", + "sha256:cda706a2ccfb032cf41fa8cc6575cbca29634fed2d226fc789e4a8daf44ab7c1" + ], + "version": "==0.6.9" + }, + "msrestazure": { + "hashes": [ + "sha256:070220fa9c86b55026360435b655d1d67ff4306fd1412687c400dc549e9647b7", + "sha256:e9d525b11d88f1073744e128ae19a4e023e4085893cfcfd02483fdd4cee25091" + ], + "version": "==0.6.1" + }, + "oauthlib": { + "hashes": [ + "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889", + "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea" + ], + "version": "==3.1.0" + }, + "paramiko": { + "hashes": [ + "sha256:99f0179bdc176281d21961a003ffdb2ec369daac1a1007241f53374e376576cf", + "sha256:f4b2edfa0d226b70bd4ca31ea7e389325990283da23465d572ed1f70a7583041" + ], + "version": "==2.6.0" + }, + "portalocker": { + "hashes": [ + "sha256:3f2a56d3d90e2ac5659ee744336e6953c0050bb61fccb97090a03de5c2a4db9f", + "sha256:95ec72fd36c230b92634dcffde65686e585a9a8569b9ba806dff41f56e255fbf" + ], + "version": "==1.2.1" + }, + "prompt-toolkit": { + "hashes": [ + "sha256:1e71341526efa4b11bb44d323e687a5d9cef204aabe2907e3f0dc1534cda0ecc", + "sha256:955d81315bb7a049f19cd17d1a73f1a40861483260f7dffd825e98303a8bd6b6", + "sha256:c1cedd626e08b8ee830ee65897de754113ff3f3035880030c08b01674d85c5b4" + ], + "version": "==1.0.16" + }, + "psutil": { + "hashes": [ + "sha256:028a1ec3c6197eadd11e7b46e8cc2f0720dc18ac6d7aabdb8e8c0d6c9704f000", + "sha256:503e4b20fa9d3342bcf58191bbc20a4a5ef79ca7df8972e6197cc14c5513e73d", + "sha256:863a85c1c0a5103a12c05a35e59d336e1d665747e531256e061213e2e90f63f3", + "sha256:954f782608bfef9ae9f78e660e065bd8ffcfaea780f9f2c8a133bb7cb9e826d7", + "sha256:b6e08f965a305cd84c2d07409bc16fbef4417d67b70c53b299116c5b895e3f45", + "sha256:bc96d437dfbb8865fc8828cf363450001cb04056bbdcdd6fc152c436c8a74c61", + "sha256:cf49178021075d47c61c03c0229ac0c60d5e2830f8cab19e2d88e579b18cdb76", + "sha256:d5350cb66690915d60f8b233180f1e49938756fb2d501c93c44f8fb5b970cc63", + "sha256:eba238cf1989dfff7d483c029acb0ac4fcbfc15de295d682901f0e2497e6781a" + ], + "version": "==5.6.3" + }, "pycparser": { "hashes": [ "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" ], "version": "==2.19" }, + "pygments": { + "hashes": [ + "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", + "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + ], + "version": "==2.4.2" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "version": "==1.7.1" + }, + "pynacl": { + "hashes": [ + "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255", + "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c", + "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e", + "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae", + "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621", + "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56", + "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39", + "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310", + "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1", + "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a", + "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786", + "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b", + "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b", + "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f", + "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20", + "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415", + "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715", + "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1", + "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0" + ], + "version": "==1.3.0" + }, + "pyopenssl": { + "hashes": [ + "sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200", + "sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6" + ], + "version": "==19.0.0" + }, + "pyperclip": { + "hashes": [ + "sha256:979325468ccf682104d5dcaf753f869868100631301d3e72f47babdea5700d1c" + ], + "version": "==1.7.0" + }, "pyrsistent": { "hashes": [ "sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533" @@ -197,6 +1347,13 @@ "index": "pypi", "version": "==0.1.11" }, + "pytz": { + "hashes": [ + "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", + "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7" + ], + "version": "==2019.2" + }, "pyyaml": { "hashes": [ "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", @@ -216,6 +1373,20 @@ "index": "pypi", "version": "==5.1.2" }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "version": "==2.22.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57", + "sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140" + ], + "version": "==1.2.0" + }, "s3transfer": { "hashes": [ "sha256:6efc926738a3cd576c2a79725fed9afde92378aa5c6a957e3af010cb019fac9d", @@ -223,6 +1394,13 @@ ], "version": "==0.2.1" }, + "scp": { + "hashes": [ + "sha256:26c0bbc7ea29c30ec096ae67b0afa7a6b7c557b2ce8f740109ee72a0d52af7d1", + "sha256:ef9d6e67c0331485d3db146bf9ee9baff8a48f3eb0e6c08276a8584b13bf34b3" + ], + "version": "==0.13.2" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", @@ -230,6 +1408,18 @@ ], "version": "==1.12.0" }, + "sshtunnel": { + "hashes": [ + "sha256:c813fdcda8e81c3936ffeac47cb69cfb2d1f5e77ad0de656c6dab56aeebd9249" + ], + "version": "==0.1.5" + }, + "tabulate": { + "hashes": [ + "sha256:8af07a39377cee1103a5c8b3330a421c2d99b9141e9cc5ddd2e3263fea416943" + ], + "version": "==0.8.3" + }, "terraform-bin": { "hashes": [ "sha256:af59ff1e59f620b7db88fd11411572aeab406d0759caa6028eaa01b9b3a9fc01" @@ -238,12 +1428,56 @@ "version": "==1.0.1" }, "urllib3": { + "extras": [ + "secure" + ], "hashes": [ "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" ], "markers": "python_version >= '3.4'", "version": "==1.25.3" + }, + "vsts": { + "hashes": [ + "sha256:c5595a42c9447888ebc91494d2db03c2b867cbca9f1f5f05c113261b92383e35", + "sha256:da179160121f5b38be061dbff29cd2b60d5d029b2207102454d77a7114e64f97" + ], + "version": "==0.1.25" + }, + "vsts-cd-manager": { + "hashes": [ + "sha256:0bb09059cd553e1c206e92ef324cb0dcf92334846d646c44c684f6256b86447b" + ], + "version": "==1.0.2" + }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + }, + "websocket-client": { + "hashes": [ + "sha256:1151d5fb3a62dc129164292e1227655e4bbc5dd5340a5165dfae61128ec50aa9", + "sha256:1fd5520878b68b84b5748bb30e592b10d0a91529d5383f74f4964e72b297fd3a" + ], + "version": "==0.56.0" + }, + "wheel": { + "hashes": [ + "sha256:9515fe0a94e823fd90b08d22de45d7bde57c90edce705b22f5e1ecf7e1b653c8", + "sha256:e721e53864f084f956f40f96124a74da0631ac13fbbd1ba99e8e2b5e9cafdf64" + ], + "version": "==0.30.0" + }, + "xmltodict": { + "hashes": [ + "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21", + "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051" + ], + "version": "==0.12.0" } }, "develop": { @@ -405,6 +1639,9 @@ "version": "==1.13.0" }, "urllib3": { + "extras": [ + "secure" + ], "hashes": [ "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" @@ -428,11 +1665,10 @@ }, "wheel": { "hashes": [ - "sha256:5e79117472686ac0c4aef5bad5172ea73a1c2d1646b808c35926bd26bdfb0c08", - "sha256:62fcfa03d45b5b722539ccbc07b190e4bfff4bb9e3a4d470dd9f6a0981002565" + "sha256:9515fe0a94e823fd90b08d22de45d7bde57c90edce705b22f5e1ecf7e1b653c8", + "sha256:e721e53864f084f956f40f96124a74da0631ac13fbbd1ba99e8e2b5e9cafdf64" ], - "index": "pypi", - "version": "==0.33.4" + "version": "==0.30.0" }, "zipp": { "hashes": [ diff --git a/core/src/epicli/cli/engine/EpiphanyEngine.py b/core/src/epicli/cli/engine/EpiphanyEngine.py index fe2f3e5266..dd85868502 100644 --- a/core/src/epicli/cli/engine/EpiphanyEngine.py +++ b/core/src/epicli/cli/engine/EpiphanyEngine.py @@ -103,7 +103,7 @@ def apply(self): template_generator.run() # Run Terraform to create infrastructure - with TerraformRunner(self.cluster_model.specification.name) as tf_runner: + with TerraformRunner(self.cluster_model) as tf_runner: tf_runner.run() self.process_configuration_docs() diff --git a/core/src/epicli/cli/engine/TerraformCommand.py b/core/src/epicli/cli/engine/TerraformCommand.py index 03da97f947..a97656e9b7 100644 --- a/core/src/epicli/cli/engine/TerraformCommand.py +++ b/core/src/epicli/cli/engine/TerraformCommand.py @@ -13,37 +13,39 @@ def __init__(self, working_directory=os.path.dirname(__file__)): self.INIT_COMMAND = "init" self.working_directory = working_directory - def apply(self, auto_approve=False): - self.run(self, self.APPLY_COMMAND, auto_approve=auto_approve) + def apply(self, auto_approve=False, env=os.environ.copy()): + self.run(self, self.APPLY_COMMAND, auto_approve=auto_approve, env=env) - def destroy(self, auto_approve=False): - self.run(self, self.DESTROY_COMMAND, auto_approve=auto_approve) + def destroy(self, auto_approve=False, env=os.environ.copy()): + self.run(self, self.DESTROY_COMMAND, auto_approve=auto_approve, env=env) - def plan(self): - self.run(self, self.PLAN_COMMAND) + def plan(self, env=os.environ.copy()): + self.run(self, self.PLAN_COMMAND, env=env) - def init(self): - self.run(self, self.INIT_COMMAND) + def init(self, env=os.environ.copy()): + self.run(self, self.INIT_COMMAND, env=env) @staticmethod - def run(self, command, auto_approve=False): + def run(self, command, env, auto_approve=False): cmd = ['terraform', command] if auto_approve: cmd.append('--auto-approve') if command == self.APPLY_COMMAND: - cmd.append('-state=' + self.working_directory + '/terraform.tfstate') + cmd.append(f'-state={self.working_directory}/terraform.tfstate') cmd.append(self.working_directory) self.logger.info('Running: "' + ' '.join(cmd) + '"') + cmd = ' '.join(cmd) + logpipe = LogPipe(__name__) - with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe) as sp: + with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe, env=env, shell=True) as sp: logpipe.close() if sp.returncode != 0: - raise Exception('Error running: "' + ' '.join(cmd) + '"') + raise Exception(f'Error running: "{cmd}"') else: - self.logger.info('Done running "' + ' '.join(cmd) + '"') + self.logger.info(f'Done running "{cmd}"') diff --git a/core/src/epicli/cli/engine/TerraformRunner.py b/core/src/epicli/cli/engine/TerraformRunner.py index 85aadf6f84..7fa473f0d0 100644 --- a/core/src/epicli/cli/engine/TerraformRunner.py +++ b/core/src/epicli/cli/engine/TerraformRunner.py @@ -1,19 +1,45 @@ +import os from cli.engine.TerraformCommand import TerraformCommand +from cli.engine.azure.AzureCommand import AzureCommand from cli.helpers.Step import Step -from cli.helpers.build_saver import get_terraform_path +from cli.helpers.build_saver import get_terraform_path, save_sp, SP_FILE_NAME +from cli.helpers.data_loader import load_yaml_file class TerraformRunner(Step): - def __init__(self, cluster_name): + def __init__(self, cluster_model): super().__init__(__name__) - self.terraform = TerraformCommand(get_terraform_path(cluster_name)) + self.cluster_model = cluster_model + self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) + self.azure_cli = AzureCommand() def __enter__(self): super().__enter__() return self def run(self): - self.terraform.init() - self.terraform.apply(auto_approve=True) + new_env = os.environ.copy() + self.terraform.init(env=new_env) + #if the provider is Azure we need to login and setup service principle. + if self.cluster_model.provider == 'azure': + subscription = self.azure_cli.login(self.cluster_model.specification.cloud.subscription_name) + + if self.cluster_model.specification.cloud.use_service_principal: + sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) + if not os.path.exists(sp_file): + self.logger.info('Creating service principle') + sp = self.azure_cli.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) + save_sp(sp, self.cluster_model.specification.name) + else: + self.logger.info('Using service principle from file') + sp = load_yaml_file(sp_file) + + #Setup environment variables for Terraform when working with Azure. + new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] + new_env['ARM_TENANT_ID'] = sp['tenant'] + new_env['ARM_CLIENT_ID'] = sp['appId'] + new_env['ARM_CLIENT_SECRET'] = sp['password'] + + self.terraform.apply(auto_approve=True, env=new_env) \ No newline at end of file diff --git a/core/src/epicli/cli/engine/azure/APIProxy.py b/core/src/epicli/cli/engine/azure/APIProxy.py index 9b80e9c1f2..7af098faa2 100644 --- a/core/src/epicli/cli/engine/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/azure/APIProxy.py @@ -7,5 +7,4 @@ def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): - pass - + pass \ No newline at end of file diff --git a/core/src/epicli/cli/engine/azure/AzureCommand.py b/core/src/epicli/cli/engine/azure/AzureCommand.py new file mode 100644 index 0000000000..4ace7093de --- /dev/null +++ b/core/src/epicli/cli/engine/azure/AzureCommand.py @@ -0,0 +1,49 @@ +import json +import re +import time +from subprocess import Popen, PIPE +from cli.helpers.Log import LogPipe, Log +from cli.helpers.doc_list_helpers import select_first + + +class AzureCommand: + def __init__(self): + self.logger = Log(__name__) + + def login(self, subscription_name): + all_subscription = self.run(self, 'az login') + subscription = select_first(all_subscription, lambda x: x['name'] == subscription_name) + if subscription is None: + raise Exception(f'User does not have access to subscription: "{subscription_name}"') + self.run(self, f'az account set --subscription {subscription["id"]}') + return subscription + + def create_sp(self, app_name, subscription_id): + #TODO: make role configurable? + sp = self.run(self, f'az ad sp create-for-rbac -n "{app_name}" --role="Contributor" --scopes="/subscriptions/{subscription_id}"') + # Sleep for a while. Sometimes the call returns before the rights of the SP are finished creating. + for x in range(0, 20): + self.logger.info(f'Waiting 20 seconds...{x}') + time.sleep(1) + return sp + + @staticmethod + def run(self, cmd): + self.logger.info('Running: "' + cmd + '"') + + logpipe = LogPipe(__name__) + with Popen(cmd, stdout=PIPE, stderr=logpipe, shell=True) as sp: + logpipe.close() + try: + data = sp.stdout.read().decode('utf-8') + data = re.sub(r'\s+', '', data) + data = re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', data) + output = json.loads(data) + except: + output = {} + + if sp.returncode != 0: + raise Exception(f'Error running: "{cmd}"') + else: + self.logger.info(f'Done running "{cmd}"') + return output diff --git a/core/src/epicli/cli/engine/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/azure/InfrastructureBuilder.py index 7dd9f0b6e9..1f9b7a9394 100644 --- a/core/src/epicli/cli/engine/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/azure/InfrastructureBuilder.py @@ -1,10 +1,13 @@ from cli.helpers.Step import Step -class ConfigBuilder(Step): - def __init__(self): +class InfrastructureBuilder(Step): + def __init__(self, docs): super().__init__(__name__) + self.docs = docs def run(self): - raise NotImplementedError() + infrastructure = [] + + return infrastructure diff --git a/core/src/epicli/cli/helpers/build_saver.py b/core/src/epicli/cli/helpers/build_saver.py index d31c515571..72bc59da86 100644 --- a/core/src/epicli/cli/helpers/build_saver.py +++ b/core/src/epicli/cli/helpers/build_saver.py @@ -3,11 +3,12 @@ import os from distutils import dir_util from cli.helpers.data_loader import load_template_file, types -from cli.helpers.yaml_helpers import dump_all +from cli.helpers.yaml_helpers import dump_all, dump from cli.helpers.Config import Config TERRAFORM_OUTPUT_DIR = 'terraform/' MANIFEST_FILE_NAME = 'manifest.yml' +SP_FILE_NAME = 'sp.yml' INVENTORY_FILE_NAME = 'inventory' ANSIBLE_OUTPUT_DIR = 'ansible/' @@ -20,6 +21,14 @@ def save_manifest(docs, cluster_name, manifest_name=MANIFEST_FILE_NAME): return path +def save_sp(service_principle, cluster_name): + terraform_dir = get_terraform_path(cluster_name) + path = os.path.join(terraform_dir, SP_FILE_NAME) + with open(path, 'w') as stream: + dump(service_principle, stream) + return path + + def save_inventory(inventory, cluster_model): cluster_name = cluster_model.specification.name build_dir = get_build_path(cluster_name) diff --git a/core/src/epicli/cli/helpers/data_loader.py b/core/src/epicli/cli/helpers/data_loader.py index 1700834b54..d4f35c345e 100644 --- a/core/src/epicli/cli/helpers/data_loader.py +++ b/core/src/epicli/cli/helpers/data_loader.py @@ -29,12 +29,17 @@ def load_yaml_obj(file_type, provider, kind): script_dir = os.path.dirname(__file__) path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, provider, file_type, kind+'.yml') if os.path.isfile(path_to_file): + return load_yaml_file(path_to_file) with open(path_to_file, 'r') as stream: return safe_load(stream) else: path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, 'common', file_type, kind + '.yml') - with open(path_to_file, 'r') as stream: - return safe_load(stream) + return load_yaml_file(path_to_file) + + +def load_yaml_file(path_to_file): + with open(path_to_file, 'r') as stream: + return safe_load(stream) def load_all_yaml_objs(file_type, provider, kind): diff --git a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 index 12bf580733..f853cd59dd 100644 --- a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 +++ b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 @@ -1 +1,19 @@ -# TODO: Fill template +##################################################### +# DO NOT Modify by hand - Manage by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +provider "azurerm" { +} + +resource "azurerm_resource_group" "rg" { + name = "{{ specification.cloud.resource_group_name }}" + location = "{{ specification.cloud.region }}" +} diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 783e34901a..2ecfb928f5 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -11,8 +11,10 @@ specification: key_path: /root/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH cloud: subscription_name: YOUR-SUB-NAME + resource_group_name: YOUR-RESOURCE-GROUP-NAME vnet_address_pool: 10.1.0.0/20 use_public_ips: False # When not using public IPs you have to provide connectivity via private IPs (VPN) + use_service_principal: False region: eu-west-2 credentials: # todo change it to get credentials from vault key: 3124-4124-4124 From 6c2671b0c8ab6630d33d63f95bac00d7f44a921f Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 9 Aug 2019 10:13:28 +0200 Subject: [PATCH 15/57] VSCode remote Remote Python Development (#431) - Added Added VS Remote-Containers development - Cleaned up some files - Fixed terraform schema change where it could not find the key after subsequent build - Set fixed version of python to 3.7 --- core/src/epicli/.devcontainer/Dockerfile | 29 +++++++++++++++++++ .../epicli/.devcontainer/devcontainer.json | 12 ++++++++ core/src/epicli/.gitignore | 6 ++-- core/src/epicli/.vscode/extensions.json | 9 ++++++ core/src/epicli/.vscode/launch.json | 19 ++++++++++++ .../cli/engine/aws/InfrastructureBuilder.py | 4 +-- core/src/epicli/epicli.code-workspace | 23 --------------- core/src/epicli/run-tests.bat | 4 --- core/src/epicli/run-tests.sh | 2 +- 9 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 core/src/epicli/.devcontainer/Dockerfile create mode 100644 core/src/epicli/.devcontainer/devcontainer.json create mode 100644 core/src/epicli/.vscode/extensions.json create mode 100644 core/src/epicli/.vscode/launch.json delete mode 100644 core/src/epicli/epicli.code-workspace delete mode 100755 core/src/epicli/run-tests.bat diff --git a/core/src/epicli/.devcontainer/Dockerfile b/core/src/epicli/.devcontainer/Dockerfile new file mode 100644 index 0000000000..a8894aa634 --- /dev/null +++ b/core/src/epicli/.devcontainer/Dockerfile @@ -0,0 +1,29 @@ +FROM python:3.7 + +ENV DEBIAN_FRONTEND=noninteractive + +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \ + + && apt-get -y install git procps lsb-release gcc make musl-dev libffi-dev tar unzip \ + + && pip --disable-pip-version-check --no-cache-dir install pipenv \ + + && groupadd --gid $USER_GID $USERNAME \ + && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \ + + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +ENV DEBIAN_FRONTEND= + + diff --git a/core/src/epicli/.devcontainer/devcontainer.json b/core/src/epicli/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..175e8fcc20 --- /dev/null +++ b/core/src/epicli/.devcontainer/devcontainer.json @@ -0,0 +1,12 @@ +{ + "name": "epicli", + "dockerFile": "Dockerfile", + "extensions": [ + "ms-python.python" + ], + "settings": { + "python.pythonPath": "/usr/local/bin/python", + }, + "postCreateCommand": "sudo pipenv install --system --dev", + "runArgs": [ "-u", "vscode" ] +} diff --git a/core/src/epicli/.gitignore b/core/src/epicli/.gitignore index cb38319c03..ea671e8354 100644 --- a/core/src/epicli/.gitignore +++ b/core/src/epicli/.gitignore @@ -121,8 +121,8 @@ dmypy.json # pycharm settings .idea/ -# external packages for BDS scan +# epicli specific external/ - -# test results tests_result/ +.terraform +clusters diff --git a/core/src/epicli/.vscode/extensions.json b/core/src/epicli/.vscode/extensions.json new file mode 100644 index 0000000000..48e9733c10 --- /dev/null +++ b/core/src/epicli/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "ms-python.python", + "vscoss.vscode-ansible", + "wholroyd.jinja", + "redhat.vscode-yaml", + "ms-vscode-remote.remote-containers" + ] +} \ No newline at end of file diff --git a/core/src/epicli/.vscode/launch.json b/core/src/epicli/.vscode/launch.json new file mode 100644 index 0000000000..571d43e0fd --- /dev/null +++ b/core/src/epicli/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "epicli", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + } + ] +} \ No newline at end of file diff --git a/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py b/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py index 4a55adcd8d..ec5dec2eb7 100644 --- a/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py @@ -192,8 +192,8 @@ def get_public_key(self): tfstate_path = get_terraform_path(self.cluster_model.specification.name) + '/terraform.tfstate' if os.path.isfile(tfstate_path): tfstate = load_json_obj(tfstate_path) - public_key_config.specification.key_name = \ - tfstate['modules'][0]['resources']['aws_key_pair.' + public_key_config.specification.name]['primary']['id'] + key_pair = select_first(tfstate['resources'], lambda x: x['type'] == 'aws_key_pair') + public_key_config.specification.key_name = key_pair['instances'][0]['attributes']['id'] else: public_key_config.specification.key_name = self.cluster_model.specification.admin_user.name + '-' \ + str(uuid.uuid4()) diff --git a/core/src/epicli/epicli.code-workspace b/core/src/epicli/epicli.code-workspace deleted file mode 100644 index 09ecdbb940..0000000000 --- a/core/src/epicli/epicli.code-workspace +++ /dev/null @@ -1,23 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "launch": { - "version": "0.2.0", - "configurations": [ - { - "name": "Python: epicli.py", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/cli/epicli.py", - "cwd": "${workspaceFolder}", - "pythonPath": "${config:python.pythonPath}", - "env": { "PYTHONPATH": "${workspaceFolder}" }, - "console": "integratedTerminal", - "args": ["apply", "-f", "data_yaml_path"] - } - ] - } -} \ No newline at end of file diff --git a/core/src/epicli/run-tests.bat b/core/src/epicli/run-tests.bat deleted file mode 100755 index 87bf2625dd..0000000000 --- a/core/src/epicli/run-tests.bat +++ /dev/null @@ -1,4 +0,0 @@ -:: Run the python test for Epicli -mkdir -p tests_result -pipenv run python -m pytest ./tests/ > tests_result/result.txt -echo "Done running tests. See tests_result/result.txt" \ No newline at end of file diff --git a/core/src/epicli/run-tests.sh b/core/src/epicli/run-tests.sh index 355e00b6c7..4cc2e8e47c 100755 --- a/core/src/epicli/run-tests.sh +++ b/core/src/epicli/run-tests.sh @@ -1,4 +1,4 @@ # Run the python test for Epicli mkdir -p tests_result -pipenv run python -m pytest ./tests/ > tests_result/result.txt +python -m pytest ./tests/ > tests_result/result.txt echo "Done running tests. See tests_result/result.txt" \ No newline at end of file From cc95462e99d9788a7c6ed34361fadbbb6c5cf881 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 9 Aug 2019 14:45:13 +0200 Subject: [PATCH 16/57] Azure complete run through (#432) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * Updates for Azure provider. - Added pylint to devdocker for better coding in VSCode (Should be PEP8 but that has some issues for now) - Moved AzureCommand to APIProxy to be in line with other AWS and any provider - Filled in Azure provider blanks so entire run will pass. - Added .devcontainer and .vscode to gitignore so people don't accidently push changes for VSCode workspace. --- core/src/epicli/.devcontainer/Dockerfile | 2 + core/src/epicli/.gitignore | 2 + core/src/epicli/cli/engine/EpiphanyEngine.py | 2 +- core/src/epicli/cli/engine/TerraformRunner.py | 23 ++++--- core/src/epicli/cli/engine/aws/APIProxy.py | 4 +- core/src/epicli/cli/engine/azure/APIProxy.py | 65 ++++++++++++++++++- .../epicli/cli/engine/azure/AzureCommand.py | 49 -------------- .../azure/InfrastructureConfigCollector.py | 20 ++++++ 8 files changed, 105 insertions(+), 62 deletions(-) delete mode 100644 core/src/epicli/cli/engine/azure/AzureCommand.py create mode 100644 core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py diff --git a/core/src/epicli/.devcontainer/Dockerfile b/core/src/epicli/.devcontainer/Dockerfile index a8894aa634..9de4bb890c 100644 --- a/core/src/epicli/.devcontainer/Dockerfile +++ b/core/src/epicli/.devcontainer/Dockerfile @@ -11,6 +11,8 @@ RUN apt-get update \ && apt-get -y install git procps lsb-release gcc make musl-dev libffi-dev tar unzip \ + && pip --disable-pip-version-check --no-cache-dir install pylint \ + && pip --disable-pip-version-check --no-cache-dir install pipenv \ && groupadd --gid $USER_GID $USERNAME \ diff --git a/core/src/epicli/.gitignore b/core/src/epicli/.gitignore index ea671e8354..090eebf267 100644 --- a/core/src/epicli/.gitignore +++ b/core/src/epicli/.gitignore @@ -126,3 +126,5 @@ external/ tests_result/ .terraform clusters +.vscode +.devcontainer diff --git a/core/src/epicli/cli/engine/EpiphanyEngine.py b/core/src/epicli/cli/engine/EpiphanyEngine.py index dd85868502..426c3b0f6c 100644 --- a/core/src/epicli/cli/engine/EpiphanyEngine.py +++ b/core/src/epicli/cli/engine/EpiphanyEngine.py @@ -103,7 +103,7 @@ def apply(self): template_generator.run() # Run Terraform to create infrastructure - with TerraformRunner(self.cluster_model) as tf_runner: + with TerraformRunner(self.cluster_model, self.configuration_docs) as tf_runner: tf_runner.run() self.process_configuration_docs() diff --git a/core/src/epicli/cli/engine/TerraformRunner.py b/core/src/epicli/cli/engine/TerraformRunner.py index 7fa473f0d0..65a23e7bd6 100644 --- a/core/src/epicli/cli/engine/TerraformRunner.py +++ b/core/src/epicli/cli/engine/TerraformRunner.py @@ -1,6 +1,6 @@ import os from cli.engine.TerraformCommand import TerraformCommand -from cli.engine.azure.AzureCommand import AzureCommand +from cli.engine.azure.APIProxy import APIProxy from cli.helpers.Step import Step from cli.helpers.build_saver import get_terraform_path, save_sp, SP_FILE_NAME from cli.helpers.data_loader import load_yaml_file @@ -8,11 +8,11 @@ class TerraformRunner(Step): - def __init__(self, cluster_model): + def __init__(self, cluster_model, config_docs): super().__init__(__name__) self.cluster_model = cluster_model + self.config_docs = config_docs self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) - self.azure_cli = AzureCommand() def __enter__(self): super().__enter__() @@ -22,21 +22,26 @@ def run(self): new_env = os.environ.copy() self.terraform.init(env=new_env) - #if the provider is Azure we need to login and setup service principle. + # From the 4 methods terraform provides to login to + # Azure we support (https://www.terraform.io/docs/providers/azurerm/auth/azure_cli.html): + # - Authenticating to Azure using the Azure CLI + # - Authenticating to Azure using a Service Principal and a Client Secret if self.cluster_model.provider == 'azure': - subscription = self.azure_cli.login(self.cluster_model.specification.cloud.subscription_name) + apiproxy = APIProxy(self.cluster_model, self.config_docs) + subscription = apiproxy.login() + apiproxy.set_active_subscribtion(subscription['id']) if self.cluster_model.specification.cloud.use_service_principal: sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) if not os.path.exists(sp_file): - self.logger.info('Creating service principle') - sp = self.azure_cli.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) + self.logger.info('Creating service principal') + sp = apiproxy.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) save_sp(sp, self.cluster_model.specification.name) else: - self.logger.info('Using service principle from file') + self.logger.info('Using service principal from file') sp = load_yaml_file(sp_file) - #Setup environment variables for Terraform when working with Azure. + #Setup environment variables for Terraform when working with Azure and service principal. new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] new_env['ARM_TENANT_ID'] = sp['tenant'] new_env['ARM_CLIENT_ID'] = sp['appId'] diff --git a/core/src/epicli/cli/engine/aws/APIProxy.py b/core/src/epicli/cli/engine/aws/APIProxy.py index bfdc80ae4a..69a868974c 100644 --- a/core/src/epicli/cli/engine/aws/APIProxy.py +++ b/core/src/epicli/cli/engine/aws/APIProxy.py @@ -22,7 +22,7 @@ def __exit__(self, exc_type, exc_value, traceback): # Query AWS API for ec2 instances in state 'running' which are in cluster's VPC # and tagged with feature name (e.g. kubernetes_master) and cluster name - def get_ips_for_feature(self, feature_key): + def get_ips_for_feature(self, component_key): cluster_name = self.cluster_model.specification.name.lower() look_for_public_ip = self.cluster_model.specification.cloud.use_public_ips vpc_id = self.get_vpc_id() @@ -37,7 +37,7 @@ def get_ips_for_feature(self, feature_key): 'Values': [vpc_id] }, { - 'Name': 'tag:'+feature_key, + 'Name': 'tag:'+component_key, 'Values': [''] }, { diff --git a/core/src/epicli/cli/engine/azure/APIProxy.py b/core/src/epicli/cli/engine/azure/APIProxy.py index 7af098faa2..5cd82f8f6b 100644 --- a/core/src/epicli/cli/engine/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/azure/APIProxy.py @@ -1,10 +1,73 @@ +import json +import re +import time +from subprocess import Popen, PIPE +from cli.helpers.Log import LogPipe, Log +from cli.helpers.doc_list_helpers import select_first + class APIProxy: def __init__(self, cluster_model, config_docs): self.cluster_model = cluster_model self.config_docs = config_docs + self.logger = Log(__name__) def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): - pass \ No newline at end of file + pass + + def login(self): + subscription_name = self.cluster_model.specification.cloud.subscription_name + all_subscription = self.run(self, 'az login') + subscription = select_first(all_subscription, lambda x: x['name'] == subscription_name) + if subscription is None: + raise Exception(f'User does not have access to subscription: "{subscription_name}"') + return subscription + + def set_active_subscribtion(self, subscription_id): + self.run(self, f'az account set --subscription {subscription_id}') + + def get_active_subscribtion(self): + subscription = self.run(self, f'az account show') + return subscription + + def create_sp(self, app_name, subscription_id): + #TODO: make role configurable? + sp = self.run(self, f'az ad sp create-for-rbac -n "{app_name}" --role="Contributor" --scopes="/subscriptions/{subscription_id}"') + # Sleep for a while. Sometimes the call returns before the rights of the SP are finished creating. + self.wait(self, 20) + return sp + + def get_ips_for_feature(self, component_key): + result = [] + #TODO: Implement this. + #az vm list-ip-addresses -g {{ resource_group_name }} + return result + + @staticmethod + def wait(self, seconds): + for x in range(0, seconds): + self.logger.info(f'Waiting {seconds} seconds...{x}') + time.sleep(1) + + @staticmethod + def run(self, cmd): + self.logger.info('Running: "' + cmd + '"') + + logpipe = LogPipe(__name__) + with Popen(cmd, stdout=PIPE, stderr=logpipe, shell=True) as sp: + logpipe.close() + try: + data = sp.stdout.read().decode('utf-8') + data = re.sub(r'\s+', '', data) + data = re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', data) + output = json.loads(data) + except: + output = {} + + if sp.returncode != 0: + raise Exception(f'Error running: "{cmd}"') + else: + self.logger.info(f'Done running "{cmd}"') + return output \ No newline at end of file diff --git a/core/src/epicli/cli/engine/azure/AzureCommand.py b/core/src/epicli/cli/engine/azure/AzureCommand.py deleted file mode 100644 index 4ace7093de..0000000000 --- a/core/src/epicli/cli/engine/azure/AzureCommand.py +++ /dev/null @@ -1,49 +0,0 @@ -import json -import re -import time -from subprocess import Popen, PIPE -from cli.helpers.Log import LogPipe, Log -from cli.helpers.doc_list_helpers import select_first - - -class AzureCommand: - def __init__(self): - self.logger = Log(__name__) - - def login(self, subscription_name): - all_subscription = self.run(self, 'az login') - subscription = select_first(all_subscription, lambda x: x['name'] == subscription_name) - if subscription is None: - raise Exception(f'User does not have access to subscription: "{subscription_name}"') - self.run(self, f'az account set --subscription {subscription["id"]}') - return subscription - - def create_sp(self, app_name, subscription_id): - #TODO: make role configurable? - sp = self.run(self, f'az ad sp create-for-rbac -n "{app_name}" --role="Contributor" --scopes="/subscriptions/{subscription_id}"') - # Sleep for a while. Sometimes the call returns before the rights of the SP are finished creating. - for x in range(0, 20): - self.logger.info(f'Waiting 20 seconds...{x}') - time.sleep(1) - return sp - - @staticmethod - def run(self, cmd): - self.logger.info('Running: "' + cmd + '"') - - logpipe = LogPipe(__name__) - with Popen(cmd, stdout=PIPE, stderr=logpipe, shell=True) as sp: - logpipe.close() - try: - data = sp.stdout.read().decode('utf-8') - data = re.sub(r'\s+', '', data) - data = re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', data) - output = json.loads(data) - except: - output = {} - - if sp.returncode != 0: - raise Exception(f'Error running: "{cmd}"') - else: - self.logger.info(f'Done running "{cmd}"') - return output diff --git a/core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py b/core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py new file mode 100644 index 0000000000..36e677f4a7 --- /dev/null +++ b/core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py @@ -0,0 +1,20 @@ +from cli.helpers.Step import Step +from cli.helpers.doc_list_helpers import select_single + + +class InfrastructureConfigCollector(Step): + + def __init__(self, docs): + super().__init__(__name__) + self.cluster_model = select_single(docs, lambda x: x.kind == 'epiphany-cluster') + self.docs = docs + + def __enter__(self): + super().__enter__() + return self + + def __exit__(self, exc_type, exc_value, traceback): + super().__exit__(exc_type, exc_value, traceback) + + def run(self): + pass From 52ef5c28650ff5248f696f71ca846ce0b610ed49 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Mon, 12 Aug 2019 10:55:53 +0200 Subject: [PATCH 17/57] Feature/cluster delete (#436) - Added delete command - Minor refactoring of engine files - Fixed issue with ObjDict. - Refactored paths calculation for DeleteEngine - Refactored PatchEngine input. - Refactored PatchEngine copy and run structure. - Restructure projects - Fixing test - Minor fix for resource-group name. --- core/src/epicli/.vscode/extensions.json | 5 +- core/src/epicli/.vscode/settings.json | 6 + .../{EpiphanyEngine.py => BuildEngine.py} | 27 ++-- core/src/epicli/cli/engine/DeleteEngine.py | 43 ++++++ ...UserConfigInitializer.py => InitEngine.py} | 13 +- core/src/epicli/cli/engine/PatchEngine.py | 75 ++++----- core/src/epicli/cli/engine/TerraformRunner.py | 50 ------ .../engine/{ => ansible}/AnsibleCommand.py | 0 .../{ => ansible}/AnsibleInventoryCreator.py | 2 +- .../cli/engine/{ => ansible}/AnsibleRunner.py | 6 +- .../{ => ansible}/AnsibleVarsGenerator.py | 0 .../cli/engine/{any => providers}/__init__.py | 0 .../engine/{ => providers}/any/APIProxy.py | 0 .../any/InfrastructureBuilder.py | 0 .../any/InfrastructureConfigCollector.py | 0 .../engine/{aws => providers/any}/__init__.py | 0 .../engine/{ => providers}/aws/APIProxy.py | 0 .../aws/InfrastructureBuilder.py | 16 +- .../aws/InfrastructureConfigCollector.py | 2 +- .../{azure => providers/aws}/__init__.py | 0 .../engine/{ => providers}/azure/APIProxy.py | 0 .../azure/InfrastructureBuilder.py | 0 .../azure/InfrastructureConfigCollector.py | 0 .../cli/engine/providers/azure/__init__.py | 0 .../providers}/provider_class_loader.py | 2 +- .../{ => terraform}/TerraformCommand.py | 5 +- .../cli/engine/terraform/TerraformRunner.py | 60 ++++++++ .../TerraformTemplateGenerator.py | 0 core/src/epicli/cli/epicli.py | 145 ++++++++++-------- core/src/epicli/cli/helpers/Config.py | 2 +- core/src/epicli/cli/helpers/Step.py | 4 - core/src/epicli/cli/helpers/build_saver.py | 7 +- core/src/epicli/cli/helpers/data_loader.py | 23 +-- core/src/epicli/run-tests.sh | 2 +- .../aws/test_AWSConfigBuilder.py | 2 +- .../test_provider_class_loader_any.py | 22 +++ .../test_provider_class_loader_aws.py | 22 +++ .../test_provider_class_loader_azure.py | 22 +++ .../cli/helpers/test_provider_class_loader.py | 7 - 39 files changed, 351 insertions(+), 219 deletions(-) create mode 100644 core/src/epicli/.vscode/settings.json rename core/src/epicli/cli/engine/{EpiphanyEngine.py => BuildEngine.py} (91%) create mode 100644 core/src/epicli/cli/engine/DeleteEngine.py rename core/src/epicli/cli/engine/{UserConfigInitializer.py => InitEngine.py} (88%) delete mode 100644 core/src/epicli/cli/engine/TerraformRunner.py rename core/src/epicli/cli/engine/{ => ansible}/AnsibleCommand.py (100%) rename core/src/epicli/cli/engine/{ => ansible}/AnsibleInventoryCreator.py (97%) rename core/src/epicli/cli/engine/{ => ansible}/AnsibleRunner.py (93%) rename core/src/epicli/cli/engine/{ => ansible}/AnsibleVarsGenerator.py (100%) rename core/src/epicli/cli/engine/{any => providers}/__init__.py (100%) rename core/src/epicli/cli/engine/{ => providers}/any/APIProxy.py (100%) rename core/src/epicli/cli/engine/{ => providers}/any/InfrastructureBuilder.py (100%) rename core/src/epicli/cli/engine/{ => providers}/any/InfrastructureConfigCollector.py (100%) rename core/src/epicli/cli/engine/{aws => providers/any}/__init__.py (100%) rename core/src/epicli/cli/engine/{ => providers}/aws/APIProxy.py (100%) rename core/src/epicli/cli/engine/{ => providers}/aws/InfrastructureBuilder.py (97%) rename core/src/epicli/cli/engine/{ => providers}/aws/InfrastructureConfigCollector.py (96%) rename core/src/epicli/cli/engine/{azure => providers/aws}/__init__.py (100%) rename core/src/epicli/cli/engine/{ => providers}/azure/APIProxy.py (100%) rename core/src/epicli/cli/engine/{ => providers}/azure/InfrastructureBuilder.py (100%) rename core/src/epicli/cli/engine/{ => providers}/azure/InfrastructureConfigCollector.py (100%) create mode 100644 core/src/epicli/cli/engine/providers/azure/__init__.py rename core/src/epicli/cli/{helpers => engine/providers}/provider_class_loader.py (55%) rename core/src/epicli/cli/engine/{ => terraform}/TerraformCommand.py (92%) create mode 100644 core/src/epicli/cli/engine/terraform/TerraformRunner.py rename core/src/epicli/cli/engine/{ => terraform}/TerraformTemplateGenerator.py (100%) rename core/src/epicli/tests/cli/engine/{ => providers}/aws/test_AWSConfigBuilder.py (98%) create mode 100644 core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_any.py create mode 100644 core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_aws.py create mode 100644 core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_azure.py delete mode 100644 core/src/epicli/tests/cli/helpers/test_provider_class_loader.py diff --git a/core/src/epicli/.vscode/extensions.json b/core/src/epicli/.vscode/extensions.json index 48e9733c10..7223083e1e 100644 --- a/core/src/epicli/.vscode/extensions.json +++ b/core/src/epicli/.vscode/extensions.json @@ -1,9 +1,10 @@ { "recommendations": [ + "ms-vscode-remote.remote-containers", "ms-python.python", + "littlefoxteam.vscode-python-test-adapter", "vscoss.vscode-ansible", "wholroyd.jinja", - "redhat.vscode-yaml", - "ms-vscode-remote.remote-containers" + "redhat.vscode-yaml" ] } \ No newline at end of file diff --git a/core/src/epicli/.vscode/settings.json b/core/src/epicli/.vscode/settings.json new file mode 100644 index 0000000000..195be80a55 --- /dev/null +++ b/core/src/epicli/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "python.linting.enabled": true, + "python.testing.unittestEnabled": false, + "python.testing.nosetestsEnabled": false, + "python.testing.pytestEnabled": true, +} \ No newline at end of file diff --git a/core/src/epicli/cli/engine/EpiphanyEngine.py b/core/src/epicli/cli/engine/BuildEngine.py similarity index 91% rename from core/src/epicli/cli/engine/EpiphanyEngine.py rename to core/src/epicli/cli/engine/BuildEngine.py index 426c3b0f6c..fd10637c7e 100644 --- a/core/src/epicli/cli/engine/EpiphanyEngine.py +++ b/core/src/epicli/cli/engine/BuildEngine.py @@ -1,19 +1,20 @@ - import os + +from cli.helpers.Step import Step from cli.helpers.doc_list_helpers import select_single from cli.helpers.build_saver import save_manifest from cli.helpers.yaml_helpers import safe_load_all from cli.helpers.Log import Log -from cli.helpers.provider_class_loader import provider_class_loader +from cli.engine.providers.provider_class_loader import provider_class_loader from cli.engine.DefaultMerger import DefaultMerger from cli.engine.SchemaValidator import SchemaValidator from cli.engine.ConfigurationAppender import ConfigurationAppender -from cli.engine.TerraformTemplateGenerator import TerraformTemplateGenerator -from cli.engine.TerraformRunner import TerraformRunner -from cli.engine.AnsibleRunner import AnsibleRunner +from cli.engine.terraform.TerraformTemplateGenerator import TerraformTemplateGenerator +from cli.engine.terraform.TerraformRunner import TerraformRunner +from cli.engine.ansible.AnsibleRunner import AnsibleRunner -class EpiphanyEngine: +class BuildEngine(Step): def __init__(self, input_data): self.file = input_data.file self.skip_infrastructure = input_data.no_infra if hasattr(input_data, 'no_infra') else False @@ -76,7 +77,7 @@ def collect_infrastructure_config(self): [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs]) as config_collector: config_collector.run() - def verify(self): + def validate(self): try: self.process_input_docs() @@ -104,19 +105,21 @@ def apply(self): # Run Terraform to create infrastructure with TerraformRunner(self.cluster_model, self.configuration_docs) as tf_runner: - tf_runner.run() + tf_runner.build() self.process_configuration_docs() self.collect_infrastructure_config() - # Run Ansible to provision infrastructure + # Merge all the docs docs = [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs] - with AnsibleRunner(self.cluster_model, docs) as ansible_runner: - ansible_runner.run() # Save docs to manifest file - save_manifest(docs, self.cluster_model.specification.name) + save_manifest(docs, self.cluster_model.specification.name) + + # Run Ansible to provision infrastructure + with AnsibleRunner(self.cluster_model, docs) as ansible_runner: + ansible_runner.run() return 0 except Exception as e: diff --git a/core/src/epicli/cli/engine/DeleteEngine.py b/core/src/epicli/cli/engine/DeleteEngine.py new file mode 100644 index 0000000000..22c094dcb1 --- /dev/null +++ b/core/src/epicli/cli/engine/DeleteEngine.py @@ -0,0 +1,43 @@ +import os +import shutil + +from cli.helpers.Step import Step +from cli.helpers.Config import Config +from cli.helpers.build_saver import MANIFEST_FILE_NAME, TERRAFORM_OUTPUT_DIR +from cli.helpers.data_loader import load_yamls_file +from cli.helpers.doc_list_helpers import select_single +from cli.engine.terraform.TerraformRunner import TerraformRunner + +class DeleteEngine(Step): + def __init__(self, input_data): + super().__init__(__name__) + self.build_directory = input_data.build_directory + + def __enter__(self): + super().__enter__() + return self + + def __exit__(self, exc_type, exc_value, traceback): + super().__exit__(exc_type, exc_value, traceback) + + def delete(self): + try: + path_to_manifest = os.path.join(self.build_directory, MANIFEST_FILE_NAME) + if not os.path.isfile(path_to_manifest): + raise Exception('No manifest.yml inside the build folder') + + docs = load_yamls_file(path_to_manifest) + cluster_model = select_single(docs, lambda x: x.kind == 'epiphany-cluster') + + if cluster_model.provider == 'any': + raise Exception('Delete works only for cloud providers') + + with TerraformRunner(cluster_model, docs) as tf_runner: + tf_runner.delete() + + shutil.rmtree(self.build_directory, ignore_errors=True) + + return 0 + except Exception as e: + self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? + return 1 \ No newline at end of file diff --git a/core/src/epicli/cli/engine/UserConfigInitializer.py b/core/src/epicli/cli/engine/InitEngine.py similarity index 88% rename from core/src/epicli/cli/engine/UserConfigInitializer.py rename to core/src/epicli/cli/engine/InitEngine.py index eedffc8b30..b054e5090b 100644 --- a/core/src/epicli/cli/engine/UserConfigInitializer.py +++ b/core/src/epicli/cli/engine/InitEngine.py @@ -1,12 +1,13 @@ import os + from cli.helpers.Step import Step from cli.helpers.build_saver import save_manifest, get_build_path from cli.helpers.data_loader import load_all_yaml_objs, types, load_all_documents_from_folder -from cli.engine.EpiphanyEngine import EpiphanyEngine +from cli.engine.BuildEngine import BuildEngine -class UserConfigInitializer(Step): +class InitEngine(Step): def __init__(self, input_data): super().__init__(__name__) self.provider = input_data.provider @@ -19,9 +20,9 @@ def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): - super().__exit__(exc_type, exc_value, traceback) + super().__exit__(exc_type, exc_value, traceback) - def run(self): + def init(self): try: defaults = load_all_yaml_objs(types.DEFAULT, self.provider, 'configuration/minimal-cluster-config') defaults[0].specification.name = self.name @@ -40,8 +41,8 @@ def run(self): def get_full_config(self, config_docs): cluster_config_path = save_manifest(config_docs, self.name, self.name + '.yml') args = type('obj', (object,), {'file': cluster_config_path})() - with EpiphanyEngine(args) as engine: - config_docs = engine.dry_run() + with BuildEngine(args) as build: + config_docs = build.dry_run() infra_docs = load_all_documents_from_folder(self.provider, 'defaults/infrastructure') merged_docs = [*config_docs, *infra_docs] diff --git a/core/src/epicli/cli/engine/PatchEngine.py b/core/src/epicli/cli/engine/PatchEngine.py index 37a4e789c6..086b34fb1d 100644 --- a/core/src/epicli/cli/engine/PatchEngine.py +++ b/core/src/epicli/cli/engine/PatchEngine.py @@ -1,16 +1,16 @@ import os -from cli.engine.AnsibleCommand import AnsibleCommand -from cli.engine.AnsibleRunner import AnsibleRunner -from cli.helpers.Config import Config from cli.helpers.Step import Step +from cli.engine.ansible.AnsibleCommand import AnsibleCommand +from cli.engine.ansible.AnsibleRunner import AnsibleRunner +from cli.helpers.Config import Config from cli.helpers.build_saver import copy_files_recursively, copy_file, get_inventory_path_for_build class PatchEngine(Step): - - def __init__(self): + def __init__(self, input_data): super().__init__(__name__) + self.build_directory = input_data.build_directory self.ansible_command = AnsibleCommand() def __enter__(self): @@ -20,60 +20,43 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) - def run(self): - pass - - def run_upgrade(self): + def upgrade(self): try: - build_directory = Config().output_dir - build_roles_directory = os.path.join(build_directory, 'ansible/roles') - - upgrade_playbook_path = os.path.join(build_roles_directory, 'upgrade') - backup_playbook_path = os.path.join(build_roles_directory, 'backup') - recovery_playbook_path = os.path.join(build_roles_directory, 'recovery') - - upgrade_role_path = os.path.join(build_directory, 'ansible', 'upgrade.yml') - - epiphany_playbooks_path = os.path.dirname(__file__) + AnsibleRunner.ANSIBLE_PLAYBOOKS_PATH - epiphany_roles_path = os.path.join(epiphany_playbooks_path, 'roles') - - upgrade_role_source_path = os.path.join(epiphany_roles_path, 'upgrade') - backup_role_source_path = os.path.join(epiphany_roles_path, 'backup') - restore_role_source_path = os.path.join(epiphany_roles_path, 'recovery') - playbook_source_path = os.path.join(epiphany_playbooks_path, 'upgrade.yml') - - copy_files_recursively(upgrade_role_source_path, upgrade_playbook_path) - copy_files_recursively(backup_role_source_path, backup_playbook_path) - copy_files_recursively(restore_role_source_path, recovery_playbook_path) - copy_file(playbook_source_path, upgrade_role_path) - - inventory_path = get_inventory_path_for_build(build_directory) - self.ansible_command.run_playbook(inventory=inventory_path, playbook_path=upgrade_role_path) + self.upgrade_patch_files_and_run('upgrade') return 0 except Exception as e: self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? return 1 - def run_backup(self): + def backup(self): try: - build_directory = Config().output_dir - backup_role_path = os.path.join(build_directory, 'ansible', 'backup.yml') - inventory_path = get_inventory_path_for_build(build_directory) - self.ansible_command.run_playbook(inventory=inventory_path, playbook_path=backup_role_path) - + self.upgrade_patch_files_and_run('backup') return 0 except Exception as e: self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? return 1 - def run_recovery(self): + def recovery(self): try: - build_directory = Config().output_dir - backup_role_path = os.path.join(build_directory, 'ansible', 'recovery.yml') - inventory_path = get_inventory_path_for_build(build_directory) - self.ansible_command.run_playbook(inventory=inventory_path, playbook_path=backup_role_path) - + self.upgrade_patch_files_and_run('recovery') return 0 except Exception as e: self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 \ No newline at end of file + return 1 + + def upgrade_patch_files_and_run(self, action): + self.logger.info(f'Running {action}...') + + #copy role files + roles_build_path = os.path.join(self.build_directory, 'ansible/roles', action) + roles_source_path = os.path.join(AnsibleRunner.ANSIBLE_PLAYBOOKS_PATH, 'roles', action) + copy_files_recursively(roles_source_path, roles_build_path) + + #copy playbook file + playbook_build_path = os.path.join(self.build_directory, 'ansible/') + action + '.yml' + playbook_source_path = os.path.join(AnsibleRunner.ANSIBLE_PLAYBOOKS_PATH) + action + '.yml' + copy_file(playbook_source_path, playbook_build_path) + + #run the playbook + inventory_path = get_inventory_path_for_build(self.build_directory) + self.ansible_command.run_playbook(inventory=inventory_path, playbook_path=playbook_build_path) \ No newline at end of file diff --git a/core/src/epicli/cli/engine/TerraformRunner.py b/core/src/epicli/cli/engine/TerraformRunner.py deleted file mode 100644 index 65a23e7bd6..0000000000 --- a/core/src/epicli/cli/engine/TerraformRunner.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -from cli.engine.TerraformCommand import TerraformCommand -from cli.engine.azure.APIProxy import APIProxy -from cli.helpers.Step import Step -from cli.helpers.build_saver import get_terraform_path, save_sp, SP_FILE_NAME -from cli.helpers.data_loader import load_yaml_file - - -class TerraformRunner(Step): - - def __init__(self, cluster_model, config_docs): - super().__init__(__name__) - self.cluster_model = cluster_model - self.config_docs = config_docs - self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) - - def __enter__(self): - super().__enter__() - return self - - def run(self): - new_env = os.environ.copy() - self.terraform.init(env=new_env) - - # From the 4 methods terraform provides to login to - # Azure we support (https://www.terraform.io/docs/providers/azurerm/auth/azure_cli.html): - # - Authenticating to Azure using the Azure CLI - # - Authenticating to Azure using a Service Principal and a Client Secret - if self.cluster_model.provider == 'azure': - apiproxy = APIProxy(self.cluster_model, self.config_docs) - subscription = apiproxy.login() - apiproxy.set_active_subscribtion(subscription['id']) - - if self.cluster_model.specification.cloud.use_service_principal: - sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) - if not os.path.exists(sp_file): - self.logger.info('Creating service principal') - sp = apiproxy.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) - save_sp(sp, self.cluster_model.specification.name) - else: - self.logger.info('Using service principal from file') - sp = load_yaml_file(sp_file) - - #Setup environment variables for Terraform when working with Azure and service principal. - new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] - new_env['ARM_TENANT_ID'] = sp['tenant'] - new_env['ARM_CLIENT_ID'] = sp['appId'] - new_env['ARM_CLIENT_SECRET'] = sp['password'] - - self.terraform.apply(auto_approve=True, env=new_env) \ No newline at end of file diff --git a/core/src/epicli/cli/engine/AnsibleCommand.py b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py similarity index 100% rename from core/src/epicli/cli/engine/AnsibleCommand.py rename to core/src/epicli/cli/engine/ansible/AnsibleCommand.py diff --git a/core/src/epicli/cli/engine/AnsibleInventoryCreator.py b/core/src/epicli/cli/engine/ansible/AnsibleInventoryCreator.py similarity index 97% rename from core/src/epicli/cli/engine/AnsibleInventoryCreator.py rename to core/src/epicli/cli/engine/ansible/AnsibleInventoryCreator.py index c46134d6b4..5c62598cd1 100644 --- a/core/src/epicli/cli/engine/AnsibleInventoryCreator.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleInventoryCreator.py @@ -1,6 +1,6 @@ from cli.helpers.doc_list_helpers import select_single from cli.helpers.naming_helpers import to_role_name -from cli.helpers.provider_class_loader import provider_class_loader +from cli.engine.providers.provider_class_loader import provider_class_loader from cli.models.AnsibleInventoryItem import AnsibleInventoryItem from collections import defaultdict from cli.helpers.build_saver import save_inventory diff --git a/core/src/epicli/cli/engine/AnsibleRunner.py b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py similarity index 93% rename from core/src/epicli/cli/engine/AnsibleRunner.py rename to core/src/epicli/cli/engine/ansible/AnsibleRunner.py index 3ef21f4de2..3dd88eb788 100644 --- a/core/src/epicli/cli/engine/AnsibleRunner.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py @@ -1,9 +1,9 @@ import os import time -from cli.engine.AnsibleCommand import AnsibleCommand -from cli.engine.AnsibleInventoryCreator import AnsibleInventoryCreator -from cli.engine.AnsibleVarsGenerator import AnsibleVarsGenerator +from cli.engine.ansible.AnsibleCommand import AnsibleCommand +from cli.engine.ansible.AnsibleInventoryCreator import AnsibleInventoryCreator +from cli.engine.ansible.AnsibleVarsGenerator import AnsibleVarsGenerator from cli.helpers.Step import Step from cli.helpers.build_saver import get_inventory_path, get_ansible_path, copy_files_recursively from cli.helpers.naming_helpers import to_role_name diff --git a/core/src/epicli/cli/engine/AnsibleVarsGenerator.py b/core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py similarity index 100% rename from core/src/epicli/cli/engine/AnsibleVarsGenerator.py rename to core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py diff --git a/core/src/epicli/cli/engine/any/__init__.py b/core/src/epicli/cli/engine/providers/__init__.py similarity index 100% rename from core/src/epicli/cli/engine/any/__init__.py rename to core/src/epicli/cli/engine/providers/__init__.py diff --git a/core/src/epicli/cli/engine/any/APIProxy.py b/core/src/epicli/cli/engine/providers/any/APIProxy.py similarity index 100% rename from core/src/epicli/cli/engine/any/APIProxy.py rename to core/src/epicli/cli/engine/providers/any/APIProxy.py diff --git a/core/src/epicli/cli/engine/any/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/any/InfrastructureBuilder.py similarity index 100% rename from core/src/epicli/cli/engine/any/InfrastructureBuilder.py rename to core/src/epicli/cli/engine/providers/any/InfrastructureBuilder.py diff --git a/core/src/epicli/cli/engine/any/InfrastructureConfigCollector.py b/core/src/epicli/cli/engine/providers/any/InfrastructureConfigCollector.py similarity index 100% rename from core/src/epicli/cli/engine/any/InfrastructureConfigCollector.py rename to core/src/epicli/cli/engine/providers/any/InfrastructureConfigCollector.py diff --git a/core/src/epicli/cli/engine/aws/__init__.py b/core/src/epicli/cli/engine/providers/any/__init__.py similarity index 100% rename from core/src/epicli/cli/engine/aws/__init__.py rename to core/src/epicli/cli/engine/providers/any/__init__.py diff --git a/core/src/epicli/cli/engine/aws/APIProxy.py b/core/src/epicli/cli/engine/providers/aws/APIProxy.py similarity index 100% rename from core/src/epicli/cli/engine/aws/APIProxy.py rename to core/src/epicli/cli/engine/providers/aws/APIProxy.py diff --git a/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py similarity index 97% rename from core/src/epicli/cli/engine/aws/InfrastructureBuilder.py rename to core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py index ec5dec2eb7..844c239c8a 100644 --- a/core/src/epicli/cli/engine/aws/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py @@ -1,14 +1,17 @@ +import os +import uuid + from cli.helpers.doc_list_helpers import select_first from cli.helpers.data_loader import load_yaml_obj, types from cli.helpers.config_merger import merge_with_defaults -from cli.engine.aws.APIProxy import APIProxy +from cli.engine.providers.aws.APIProxy import APIProxy from cli.helpers.Step import Step from cli.helpers.doc_list_helpers import select_single, select_all from cli.helpers.build_saver import get_terraform_path from cli.helpers.data_loader import load_json_obj from cli.helpers.naming_helpers import resource_name -import os -import uuid +from cli.helpers.objdict_helpers import objdict_to_dict + class InfrastructureBuilder(Step): def __init__(self, docs): @@ -100,7 +103,7 @@ def run(self): def get_resource_group(self): resource_group = self.get_config_or_default(self.docs, 'infrastructure/resource-group') - resource_group.specification.name = self.cluster_name + resource_group.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'rg') resource_group.specification.cluster_name = self.cluster_name return resource_group @@ -234,6 +237,11 @@ def add_security_rules_inbound_efs(self, infrastructure, security_group): rule.specification.destination_address_prefix = '*' security_group.specification.rules.append(rule.specification) + rules = [] + for rule in security_group.specification.rules: + rules.append(objdict_to_dict(rule)) + security_group.specification.rules = rules + @staticmethod def efs_add_mount_target_config(efs_config, subnet): target = select_first(efs_config.specification.mount_targets, diff --git a/core/src/epicli/cli/engine/aws/InfrastructureConfigCollector.py b/core/src/epicli/cli/engine/providers/aws/InfrastructureConfigCollector.py similarity index 96% rename from core/src/epicli/cli/engine/aws/InfrastructureConfigCollector.py rename to core/src/epicli/cli/engine/providers/aws/InfrastructureConfigCollector.py index 10bd54a4fd..b3f94736d7 100644 --- a/core/src/epicli/cli/engine/aws/InfrastructureConfigCollector.py +++ b/core/src/epicli/cli/engine/providers/aws/InfrastructureConfigCollector.py @@ -1,5 +1,5 @@ from cli.helpers.Step import Step -from cli.engine.aws.APIProxy import APIProxy +from cli.engine.providers.aws.APIProxy import APIProxy from cli.helpers.doc_list_helpers import select_single, select_first diff --git a/core/src/epicli/cli/engine/azure/__init__.py b/core/src/epicli/cli/engine/providers/aws/__init__.py similarity index 100% rename from core/src/epicli/cli/engine/azure/__init__.py rename to core/src/epicli/cli/engine/providers/aws/__init__.py diff --git a/core/src/epicli/cli/engine/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py similarity index 100% rename from core/src/epicli/cli/engine/azure/APIProxy.py rename to core/src/epicli/cli/engine/providers/azure/APIProxy.py diff --git a/core/src/epicli/cli/engine/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py similarity index 100% rename from core/src/epicli/cli/engine/azure/InfrastructureBuilder.py rename to core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py diff --git a/core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py similarity index 100% rename from core/src/epicli/cli/engine/azure/InfrastructureConfigCollector.py rename to core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py diff --git a/core/src/epicli/cli/engine/providers/azure/__init__.py b/core/src/epicli/cli/engine/providers/azure/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/epicli/cli/helpers/provider_class_loader.py b/core/src/epicli/cli/engine/providers/provider_class_loader.py similarity index 55% rename from core/src/epicli/cli/helpers/provider_class_loader.py rename to core/src/epicli/cli/engine/providers/provider_class_loader.py index 1035de6d44..629b65e812 100644 --- a/core/src/epicli/cli/helpers/provider_class_loader.py +++ b/core/src/epicli/cli/engine/providers/provider_class_loader.py @@ -3,6 +3,6 @@ def provider_class_loader(provider, class_name): try: - return getattr(importlib.import_module('cli.engine.' + provider.lower() + '.' + class_name), class_name) + return getattr(importlib.import_module('cli.engine.providers.' + provider.lower() + '.' + class_name), class_name) except: raise Exception('No ' + class_name + ' for ' + provider) diff --git a/core/src/epicli/cli/engine/TerraformCommand.py b/core/src/epicli/cli/engine/terraform/TerraformCommand.py similarity index 92% rename from core/src/epicli/cli/engine/TerraformCommand.py rename to core/src/epicli/cli/engine/terraform/TerraformCommand.py index a97656e9b7..1e09502638 100644 --- a/core/src/epicli/cli/engine/TerraformCommand.py +++ b/core/src/epicli/cli/engine/terraform/TerraformCommand.py @@ -32,14 +32,13 @@ def run(self, command, env, auto_approve=False): if auto_approve: cmd.append('--auto-approve') - if command == self.APPLY_COMMAND: + if command == self.APPLY_COMMAND or command == self.DESTROY_COMMAND: cmd.append(f'-state={self.working_directory}/terraform.tfstate') cmd.append(self.working_directory) - self.logger.info('Running: "' + ' '.join(cmd) + '"') - cmd = ' '.join(cmd) + self.logger.info(f'Running: "{cmd}"') logpipe = LogPipe(__name__) with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe, env=env, shell=True) as sp: diff --git a/core/src/epicli/cli/engine/terraform/TerraformRunner.py b/core/src/epicli/cli/engine/terraform/TerraformRunner.py new file mode 100644 index 0000000000..00b8d178f9 --- /dev/null +++ b/core/src/epicli/cli/engine/terraform/TerraformRunner.py @@ -0,0 +1,60 @@ +import os +from cli.engine.terraform.TerraformCommand import TerraformCommand +from cli.engine.providers.azure.APIProxy import APIProxy +from cli.helpers.Step import Step +from cli.helpers.build_saver import get_terraform_path, save_sp, SP_FILE_NAME +from cli.helpers.data_loader import load_yaml_file + + +class TerraformRunner(Step): + + def __init__(self, cluster_model, config_docs): + super().__init__(__name__) + self.cluster_model = cluster_model + self.config_docs = config_docs + self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) + + def __enter__(self): + super().__enter__() + return self + + def run(self): + pass + + def build(self): + new_env = os.environ.copy() + self.terraform.init(env=new_env) + if self.cluster_model.provider == 'azure': + self.azure_login() + self.terraform.apply(auto_approve=True, env=new_env) + + def delete(self): + new_env = os.environ.copy() + if self.cluster_model.provider == 'azure': + self.azure_login() + self.terraform.destroy(auto_approve=True, env=new_env) + + def azure_login(self): + # From the 4 methods terraform provides to login to + # Azure we support (https://www.terraform.io/docs/providers/azurerm/auth/azure_cli.html): + # - Authenticating to Azure using the Azure CLI + # - Authenticating to Azure using a Service Principal and a Client Secret + apiproxy = APIProxy(self.cluster_model, self.config_docs) + subscription = apiproxy.login() + apiproxy.set_active_subscribtion(subscription['id']) + + if self.cluster_model.specification.cloud.use_service_principal: + sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) + if not os.path.exists(sp_file): + self.logger.info('Creating service principal') + sp = apiproxy.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) + save_sp(sp, self.cluster_model.specification.name) + else: + self.logger.info('Using service principal from file') + sp = load_yaml_file(sp_file) + + #Setup environment variables for Terraform when working with Azure and service principal. + new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] + new_env['ARM_TENANT_ID'] = sp['tenant'] + new_env['ARM_CLIENT_ID'] = sp['appId'] + new_env['ARM_CLIENT_SECRET'] = sp['password'] diff --git a/core/src/epicli/cli/engine/TerraformTemplateGenerator.py b/core/src/epicli/cli/engine/terraform/TerraformTemplateGenerator.py similarity index 100% rename from core/src/epicli/cli/engine/TerraformTemplateGenerator.py rename to core/src/epicli/cli/engine/terraform/TerraformTemplateGenerator.py diff --git a/core/src/epicli/cli/epicli.py b/core/src/epicli/cli/epicli.py index 1ce5bfbe58..5492a742c5 100644 --- a/core/src/epicli/cli/epicli.py +++ b/core/src/epicli/cli/epicli.py @@ -4,11 +4,12 @@ import json import os +from cli.engine.BuildEngine import BuildEngine from cli.engine.PatchEngine import PatchEngine -from cli.engine.UserConfigInitializer import UserConfigInitializer +from cli.engine.DeleteEngine import DeleteEngine +from cli.engine.InitEngine import InitEngine from cli.helpers.Log import Log from cli.helpers.Config import Config -from cli.engine.EpiphanyEngine import EpiphanyEngine from cli.version import VERSION from cli.licenses import LICENSES from cli.helpers.query_yes_no import query_yes_no @@ -54,6 +55,7 @@ def main(): upgrade_parser(subparsers) backup_parser(subparsers) recovery_parser(subparsers) + delete_parser(subparsers) # check if there were any variables and display full help if len(sys.argv) < 2: @@ -76,6 +78,24 @@ def main(): return args.func(args) +def init_parser(subparsers): + sub_parser = subparsers.add_parser('init', description='Creates configuration file in working directory.') + sub_parser.add_argument('-p', '--provider', dest='provider', choices=['aws', 'azure', 'any'], default='any', type=str, + required=True, help='One of the supported providers: azure|aws|any') + sub_parser.add_argument('-n', '--name', dest='name', type=str, required=True, + help='Name of the cluster.') + + sub_parser.add_argument('--full', dest='full_config', action="store_true", + help='Use this flag if you want to create verbose configuration file.') + + def run_init(args): + Config().output_dir = os.getcwd() + with InitEngine(args) as engine: + return engine.init() + + sub_parser.set_defaults(func=run_init) + + def apply_parser(subparsers): sub_parser = subparsers.add_parser('apply', description='Applies configuration from file.') sub_parser.add_argument('-f', '--file', dest='file', type=str, @@ -83,6 +103,11 @@ def apply_parser(subparsers): sub_parser.add_argument('--no-infra', dest='no_infra', action="store_true", help='Skip infrastructure provisioning.') + def run_apply(args): + adjust_paths_from_file(args) + with BuildEngine(args) as engine: + return engine.apply() + sub_parser.set_defaults(func=run_apply) @@ -92,25 +117,42 @@ def validate_parser(subparsers): 'infrastructure/configuration') sub_parser.add_argument('-f', '--file', dest='file', type=str, help='File with infrastructure/configuration definitions to use.') + + def run_validate(args): + adjust_paths_from_file(args) + with BuildEngine(args) as engine: + return engine.validate() + sub_parser.set_defaults(func=run_validate) -def init_parser(subparsers): - sub_parser = subparsers.add_parser('init', description='Creates configuration file in working directory.') - sub_parser.add_argument('-p', '--provider', dest='provider', choices=['aws', 'azure', 'any'], default='any', type=str, - required=True, help='One of the supported providers: azure|aws|any') - sub_parser.add_argument('-n', '--name', dest='name', type=str, required=True, - help='Name of the cluster.') +def delete_parser(subparsers): + sub_parser = subparsers.add_parser('delete', description='[Experimental]: Delete a cluster from build artifacts.') + sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, + help='Absolute path to directory with build artifacts.') - sub_parser.add_argument('--full', dest='full_config', action="store_true", - help='Use this flag if you want to create verbose configuration file.') - sub_parser.set_defaults(func=run_init) + def run_delete(args): + experimental_query() + if not query_yes_no('Do you really want to delete your cluster?'): + return 0 + adjust_paths_from_build(args) + with DeleteEngine(args) as engine: + return engine.delete() + + sub_parser.set_defaults(func=run_delete) def upgrade_parser(subparsers): sub_parser = subparsers.add_parser('upgrade', description='[Experimental]: Upgrades existing Epiphany Platform to latest version.') sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, help='Absolute path to directory with build artifacts.') + + def run_upgrade(args): + experimental_query() + adjust_paths_from_build(args) + with PatchEngine(args) as engine: + return engine.upgrade() + sub_parser.set_defaults(func=run_upgrade) @@ -118,6 +160,13 @@ def backup_parser(subparsers): sub_parser = subparsers.add_parser('backup', description='[Experimental]: Backups existing Epiphany Platform components.') sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, help='Absolute path to directory with build artifacts.') + + def run_backup(args): + experimental_query() + adjust_paths_from_build(args) + with PatchEngine(args) as engine: + return engine.backup() + sub_parser.set_defaults(func=run_backup) @@ -125,67 +174,41 @@ def recovery_parser(subparsers): sub_parser = subparsers.add_parser('recovery', description='[Experimental]: Recover from existing backup.') sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, help='Absolute path to directory with build artifacts.') - sub_parser.set_defaults(func=run_recovery) - - -def run_apply(args): - adjust_paths(args) - with EpiphanyEngine(args) as engine: - return engine.apply() - - -def run_validate(args): - adjust_paths(args) - with EpiphanyEngine(args) as engine: - return engine.verify() + def run_recovery(args): + experimental_query() + adjust_paths_from_build(args) + with PatchEngine(args) as engine: + return engine.recovery() -def run_init(args): - Config().output_dir = os.getcwd() - with UserConfigInitializer(args) as initializer: - return initializer.run() - - -def run_upgrade(args): - if not query_yes_no('This is an experimental feature and could change at any time. Do you want to continue?'): - return 0 - Config().output_dir = args.build_directory - with PatchEngine() as engine: - return engine.run_upgrade() - - -def run_backup(args): - if not query_yes_no('This is an experimental feature and could change at any time. Do you want to continue?'): - return 0 - Config().output_dir = args.build_directory - with PatchEngine() as engine: - return engine.run_backup() + sub_parser.set_defaults(func=run_recovery) -def run_recovery(args): +def experimental_query(): if not query_yes_no('This is an experimental feature and could change at any time. Do you want to continue?'): - return 0 - Config().output_dir = args.build_directory - with PatchEngine() as engine: - return engine.run_recovery() + sys.exit(0) -def adjust_paths(args): - args.file = get_config_file_path(args.file) - adjust_output_dir(args.file) +def adjust_paths_from_file(args): + if not os.path.isabs(args.file): + args.file = os.path.join(os.getcwd(), args.file) + if not os.path.isfile(args.file): + raise Exception(f'File "{args.file}" does not excist') + if Config().output_dir is None: + Config().output_dir = os.path.join(os.path.dirname(args.file), 'build') dump_config(Config()) -def get_config_file_path(config_file_path): - if os.path.isabs(config_file_path): - return config_file_path - return os.path.join(os.getcwd(), config_file_path) - - -def adjust_output_dir(config_file_path): +def adjust_paths_from_build(args): + if not os.path.isabs(args.build_directory): + args.build_directory = os.path.join(os.getcwd(), args.build_directory) + if not os.path.exists(args.build_directory): + raise Exception(f'Build directory "{args.build_directory}" does not excist') + if args.build_directory[-1:] == '/': + args.build_directory = args.build_directory.rstrip('/') if Config().output_dir is None: - config_directory = os.path.dirname(config_file_path) - Config().output_dir = os.path.join(config_directory, 'build') + Config().output_dir = os.path.split(args.build_directory)[0] + dump_config(Config()) def dump_config(config): diff --git a/core/src/epicli/cli/helpers/Config.py b/core/src/epicli/cli/helpers/Config.py index 54e6a3020d..36379c6bd2 100644 --- a/core/src/epicli/cli/helpers/Config.py +++ b/core/src/epicli/cli/helpers/Config.py @@ -7,7 +7,7 @@ def __init__(self): self._output_dir = None if self._docker_cli: - self._output_dir = '/shared/' + self._output_dir = '/shared/build/' self._log_file = 'log.log' self._log_format = '%(asctime)s %(levelname)s %(name)s - %(message)s' diff --git a/core/src/epicli/cli/helpers/Step.py b/core/src/epicli/cli/helpers/Step.py index dae5d57bc3..7adf21be9a 100644 --- a/core/src/epicli/cli/helpers/Step.py +++ b/core/src/epicli/cli/helpers/Step.py @@ -15,7 +15,3 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): passed = int(round((time.time() - self.start) * 1000)) self.logger.info('Run done in ' + str(passed) + 'ms') - - @abstractmethod - def run(self): - pass diff --git a/core/src/epicli/cli/helpers/build_saver.py b/core/src/epicli/cli/helpers/build_saver.py index 72bc59da86..c005ed3199 100644 --- a/core/src/epicli/cli/helpers/build_saver.py +++ b/core/src/epicli/cli/helpers/build_saver.py @@ -59,10 +59,9 @@ def save_to_file(file_path, content): def get_output_path(): - output_dir = os.path.join(os.path.dirname(__file__), Config().output_dir) - if not os.path.exists(output_dir): - os.makedirs(output_dir) - return output_dir + if not os.path.exists(Config().output_dir): + os.makedirs(Config().output_dir) + return Config().output_dir def get_build_path(cluster_name): diff --git a/core/src/epicli/cli/helpers/data_loader.py b/core/src/epicli/cli/helpers/data_loader.py index d4f35c345e..09e35f3fbd 100644 --- a/core/src/epicli/cli/helpers/data_loader.py +++ b/core/src/epicli/cli/helpers/data_loader.py @@ -30,18 +30,11 @@ def load_yaml_obj(file_type, provider, kind): path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, provider, file_type, kind+'.yml') if os.path.isfile(path_to_file): return load_yaml_file(path_to_file) - with open(path_to_file, 'r') as stream: - return safe_load(stream) else: path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, 'common', file_type, kind + '.yml') return load_yaml_file(path_to_file) -def load_yaml_file(path_to_file): - with open(path_to_file, 'r') as stream: - return safe_load(stream) - - def load_all_yaml_objs(file_type, provider, kind): script_dir = os.path.dirname(__file__) path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, provider, file_type, kind+'.yml') @@ -50,12 +43,20 @@ def load_all_yaml_objs(file_type, provider, kind): def load_file_from_path(script_dir, path_to_file, file_type, kind): if os.path.isfile(path_to_file): - with open(path_to_file, 'r') as stream: - return safe_load_all(stream) + return load_yamls_file(path_to_file) else: path_to_file = os.path.join(script_dir, DATA_FOLDER_PATH, 'common', file_type, kind + '.yml') - with open(path_to_file, 'r') as stream: - return safe_load_all(stream) + return load_yamls_file(path_to_file) + + +def load_yaml_file(path_to_file): + with open(path_to_file, 'r') as stream: + return safe_load(stream) + + +def load_yamls_file(path_to_file): + with open(path_to_file, 'r') as stream: + return safe_load_all(stream) def load_template_file(file_type, provider, kind): diff --git a/core/src/epicli/run-tests.sh b/core/src/epicli/run-tests.sh index 4cc2e8e47c..210dd95e62 100755 --- a/core/src/epicli/run-tests.sh +++ b/core/src/epicli/run-tests.sh @@ -1,4 +1,4 @@ # Run the python test for Epicli mkdir -p tests_result -python -m pytest ./tests/ > tests_result/result.txt +python -m pytest ./tests/ | tee tests_result/result.txt echo "Done running tests. See tests_result/result.txt" \ No newline at end of file diff --git a/core/src/epicli/tests/cli/engine/aws/test_AWSConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py similarity index 98% rename from core/src/epicli/tests/cli/engine/aws/test_AWSConfigBuilder.py rename to core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py index 2094a1d6ad..bd6c8044f4 100644 --- a/core/src/epicli/tests/cli/engine/aws/test_AWSConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py @@ -1,4 +1,4 @@ -from cli.engine.aws.InfrastructureBuilder import InfrastructureBuilder +from cli.engine.providers.aws.InfrastructureBuilder import InfrastructureBuilder from cli.helpers.objdict_helpers import dict_to_objdict import pytest diff --git a/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_any.py b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_any.py new file mode 100644 index 0000000000..c272176e1f --- /dev/null +++ b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_any.py @@ -0,0 +1,22 @@ +from cli.engine.providers.provider_class_loader import provider_class_loader +from cli.engine.providers.any.InfrastructureBuilder import InfrastructureBuilder +from cli.engine.providers.any.APIProxy import APIProxy +from cli.engine.providers.any.InfrastructureConfigCollector import InfrastructureConfigCollector + + +def test_provider_class_loader_infrastructurebuilder_any(): + infrastructure_builder = provider_class_loader('any', 'InfrastructureBuilder') + assert infrastructure_builder is InfrastructureBuilder + + +def test_provider_class_loader_apiproxy_any(): + api_proxy = provider_class_loader('any', 'APIProxy') + assert api_proxy is APIProxy + + +def test_provider_class_loader_infrastructureconfigcollector_any(): + infrastructure_config_collector = provider_class_loader('any', 'InfrastructureConfigCollector') + assert infrastructure_config_collector is InfrastructureConfigCollector + + + diff --git a/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_aws.py b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_aws.py new file mode 100644 index 0000000000..af9030f7e2 --- /dev/null +++ b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_aws.py @@ -0,0 +1,22 @@ +from cli.engine.providers.provider_class_loader import provider_class_loader +from cli.engine.providers.aws.InfrastructureBuilder import InfrastructureBuilder +from cli.engine.providers.aws.APIProxy import APIProxy +from cli.engine.providers.aws.InfrastructureConfigCollector import InfrastructureConfigCollector + + +def test_provider_class_loader_infrastructurebuilder_aws(): + infrastructure_builder = provider_class_loader('aws', 'InfrastructureBuilder') + assert infrastructure_builder is InfrastructureBuilder + + +def test_provider_class_loader_apiproxy_aws(): + api_proxy = provider_class_loader('aws', 'APIProxy') + assert api_proxy is APIProxy + + +def test_provider_class_loader_infrastructureconfigcollector_aws(): + infrastructure_config_collector = provider_class_loader('aws', 'InfrastructureConfigCollector') + assert infrastructure_config_collector is InfrastructureConfigCollector + + + diff --git a/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_azure.py b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_azure.py new file mode 100644 index 0000000000..e79de76f31 --- /dev/null +++ b/core/src/epicli/tests/cli/engine/providers/test_provider_class_loader_azure.py @@ -0,0 +1,22 @@ +from cli.engine.providers.provider_class_loader import provider_class_loader +from cli.engine.providers.azure.InfrastructureBuilder import InfrastructureBuilder +from cli.engine.providers.azure.APIProxy import APIProxy +from cli.engine.providers.azure.InfrastructureConfigCollector import InfrastructureConfigCollector + + +def test_provider_class_loader_infrastructurebuilder_azure(): + infrastructure_builder = provider_class_loader('azure', 'InfrastructureBuilder') + assert infrastructure_builder is InfrastructureBuilder + + +def test_provider_class_loader_apiproxy_azure(): + api_proxy = provider_class_loader('azure', 'APIProxy') + assert api_proxy is APIProxy + + +def test_provider_class_loader_infrastructureconfigcollector_azure(): + infrastructure_config_collector = provider_class_loader('azure', 'InfrastructureConfigCollector') + assert infrastructure_config_collector is InfrastructureConfigCollector + + + diff --git a/core/src/epicli/tests/cli/helpers/test_provider_class_loader.py b/core/src/epicli/tests/cli/helpers/test_provider_class_loader.py deleted file mode 100644 index 62218340a4..0000000000 --- a/core/src/epicli/tests/cli/helpers/test_provider_class_loader.py +++ /dev/null @@ -1,7 +0,0 @@ -from cli.helpers.provider_class_loader import provider_class_loader -from cli.engine.aws.InfrastructureBuilder import InfrastructureBuilder - - -def test_provider_class_loader(): - infrastructure_builder = provider_class_loader('aws', 'InfrastructureBuilder') - assert infrastructure_builder is InfrastructureBuilder From a2bb7ffdd6999bcb7b0ef5eca08eafacd34f3b67 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 13 Aug 2019 09:55:32 +0200 Subject: [PATCH 18/57] Feature/az resource group (#437) - Moved resource group creation to separate model - Added creation of VNET - Fixed env variables Azure with SP login - Fixed some typos --- .../providers/azure/InfrastructureBuilder.py | 37 ++++++++++++++++++- .../cli/engine/terraform/TerraformRunner.py | 23 +++++++----- .../data/aws/terraform/epiphany-cluster.j2 | 2 +- .../infrastructure/default-security-group.j2 | 2 +- .../terraform/infrastructure/efs-storage.j2 | 2 +- .../infrastructure/internet-gateway.j2 | 2 +- .../infrastructure/launch-configuration.j2 | 2 +- .../terraform/infrastructure/public-key.j2 | 2 +- .../infrastructure/resource-group.j2 | 2 +- .../infrastructure/route-table-association.j2 | 2 +- .../terraform/infrastructure/route-table.j2 | 2 +- .../infrastructure/security-group-rule.j2 | 2 +- .../infrastructure/security-group.j2 | 2 +- .../aws/terraform/infrastructure/subnet.j2 | 2 +- .../infrastructure/virtual-machine.j2 | 2 +- .../data/aws/terraform/infrastructure/vpc.j2 | 2 +- .../azure/defaults/infrastructure/network.yml | 7 ---- .../infrastructure/resource-group.yml | 8 ++++ .../azure/defaults/infrastructure/vnet.yml | 10 +++++ .../data/azure/terraform/epiphany-cluster.j2 | 7 +--- .../azure/terraform/infrastructure/net.j2 | 1 - .../azure/terraform/infrastructure/network.j2 | 5 --- .../infrastructure/resource-group.j2 | 17 +++++++++ .../azure/terraform/infrastructure/vnet.j2 | 18 +++++++++ .../{network.yml => resource-group.yml} | 0 .../azure/validation/infrastructure/vnet.yml | 1 + .../data/common/defaults/epiphany-cluster.yml | 1 - 27 files changed, 118 insertions(+), 45 deletions(-) delete mode 100644 core/src/epicli/data/azure/defaults/infrastructure/network.yml create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/vnet.yml delete mode 100644 core/src/epicli/data/azure/terraform/infrastructure/net.j2 delete mode 100644 core/src/epicli/data/azure/terraform/infrastructure/network.j2 create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/resource-group.j2 create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 rename core/src/epicli/data/azure/validation/infrastructure/{network.yml => resource-group.yml} (100%) create mode 100644 core/src/epicli/data/azure/validation/infrastructure/vnet.yml diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 1f9b7a9394..3f9af30d3f 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -1,13 +1,48 @@ from cli.helpers.Step import Step - +from cli.helpers.naming_helpers import resource_name +from cli.helpers.doc_list_helpers import select_single, select_all +from cli.helpers.doc_list_helpers import select_first +from cli.helpers.data_loader import load_yaml_obj, types class InfrastructureBuilder(Step): def __init__(self, docs): super().__init__(__name__) + self.cluster_model = select_single(docs, lambda x: x.kind == 'epiphany-cluster') + self.cluster_name = self.cluster_model.specification.name.lower() + self.cluster_prefix = self.cluster_model.specification.prefix.lower() + self.resource_group_name = resource_name(self.cluster_prefix, self.cluster_name, 'rg') + self.region = self.cluster_model.specification.cloud.region self.docs = docs def run(self): infrastructure = [] + resource_group = self.get_resource_group() + infrastructure.append(resource_group) + + vnet = self.get_virtual_network() + infrastructure.append(vnet) + return infrastructure + def get_resource_group(self): + resource_group = self.get_config_or_default(self.docs, 'infrastructure/resource-group') + resource_group.specification.name = self.resource_group_name + resource_group.specification.region = self.cluster_model.specification.cloud.region + return resource_group + + def get_virtual_network(self): + vnet = self.get_config_or_default(self.docs, 'infrastructure/vnet') + vnet.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vnet') + vnet.specification.address_space = self.cluster_model.specification.cloud.vnet_address_pool + vnet.specification.resource_group_name = self.resource_group_name + vnet.specification.location = self.cluster_model.specification.cloud.region + return vnet + + @staticmethod + def get_config_or_default(docs, kind): + config = select_first(docs, lambda x: x.kind == kind) + if config is None: + return load_yaml_obj(types.DEFAULT, 'azure', kind) + return config + diff --git a/core/src/epicli/cli/engine/terraform/TerraformRunner.py b/core/src/epicli/cli/engine/terraform/TerraformRunner.py index 00b8d178f9..c379367f5c 100644 --- a/core/src/epicli/cli/engine/terraform/TerraformRunner.py +++ b/core/src/epicli/cli/engine/terraform/TerraformRunner.py @@ -4,6 +4,7 @@ from cli.helpers.Step import Step from cli.helpers.build_saver import get_terraform_path, save_sp, SP_FILE_NAME from cli.helpers.data_loader import load_yaml_file +from cli.helpers.naming_helpers import resource_name class TerraformRunner(Step): @@ -13,6 +14,7 @@ def __init__(self, cluster_model, config_docs): self.cluster_model = cluster_model self.config_docs = config_docs self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) + self.new_env = os.environ.copy() def __enter__(self): super().__enter__() @@ -22,17 +24,15 @@ def run(self): pass def build(self): - new_env = os.environ.copy() - self.terraform.init(env=new_env) + self.terraform.init(env=self.new_env) if self.cluster_model.provider == 'azure': self.azure_login() - self.terraform.apply(auto_approve=True, env=new_env) + self.terraform.apply(auto_approve=True, env=self.new_env) def delete(self): - new_env = os.environ.copy() if self.cluster_model.provider == 'azure': self.azure_login() - self.terraform.destroy(auto_approve=True, env=new_env) + self.terraform.destroy(auto_approve=True, env=self.new_env) def azure_login(self): # From the 4 methods terraform provides to login to @@ -47,14 +47,17 @@ def azure_login(self): sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) if not os.path.exists(sp_file): self.logger.info('Creating service principal') - sp = apiproxy.create_sp(self.cluster_model.specification.cloud.resource_group_name, subscription['id']) + cluster_name = self.cluster_model.specification.name.lower() + cluster_prefix = self.cluster_model.specification.prefix.lower() + resource_group_name = resource_name(cluster_prefix, cluster_name, 'rg') + sp = apiproxy.create_sp(resource_group_name, subscription['id']) save_sp(sp, self.cluster_model.specification.name) else: self.logger.info('Using service principal from file') sp = load_yaml_file(sp_file) #Setup environment variables for Terraform when working with Azure and service principal. - new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] - new_env['ARM_TENANT_ID'] = sp['tenant'] - new_env['ARM_CLIENT_ID'] = sp['appId'] - new_env['ARM_CLIENT_SECRET'] = sp['password'] + self.new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] + self.new_env['ARM_TENANT_ID'] = sp['tenant'] + self.new_env['ARM_CLIENT_ID'] = sp['appId'] + self.new_env['ARM_CLIENT_SECRET'] = sp['password'] diff --git a/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 b/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 index 9ead9d53a8..6fbdc1d37e 100644 --- a/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 +++ b/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/default-security-group.j2 b/core/src/epicli/data/aws/terraform/infrastructure/default-security-group.j2 index 38481111d2..62e81a8511 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/default-security-group.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/default-security-group.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 b/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 index a98be6c7e8..7b74e429bd 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/efs-storage.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 b/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 index 52a0f4d099..a911226da4 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/internet-gateway.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 b/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 index f4687ad76c..9c9b7fff9a 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/launch-configuration.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/public-key.j2 b/core/src/epicli/data/aws/terraform/infrastructure/public-key.j2 index 8d24d59718..8b92c58736 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/public-key.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/public-key.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/resource-group.j2 b/core/src/epicli/data/aws/terraform/infrastructure/resource-group.j2 index eda3926457..1d1e0501fa 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/resource-group.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/resource-group.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/route-table-association.j2 b/core/src/epicli/data/aws/terraform/infrastructure/route-table-association.j2 index 2ed79bd14b..81349c3167 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/route-table-association.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/route-table-association.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 b/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 index f7143b3e5e..4918839328 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/route-table.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/security-group-rule.j2 b/core/src/epicli/data/aws/terraform/infrastructure/security-group-rule.j2 index dbbe3df6a0..788f9f07b2 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/security-group-rule.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/security-group-rule.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 b/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 index 4db45f6c9a..8bfb1ba812 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/security-group.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/subnet.j2 b/core/src/epicli/data/aws/terraform/infrastructure/subnet.j2 index 48e4a8c821..45d985dca1 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/subnet.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/subnet.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/virtual-machine.j2 b/core/src/epicli/data/aws/terraform/infrastructure/virtual-machine.j2 index 538d6798db..0f5b88abba 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/virtual-machine.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/virtual-machine.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 b/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 index a103ffd1c1..b9e026b042 100644 --- a/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 +++ b/core/src/epicli/data/aws/terraform/infrastructure/vpc.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much diff --git a/core/src/epicli/data/azure/defaults/infrastructure/network.yml b/core/src/epicli/data/azure/defaults/infrastructure/network.yml deleted file mode 100644 index 11f72ce882..0000000000 --- a/core/src/epicli/data/azure/defaults/infrastructure/network.yml +++ /dev/null @@ -1,7 +0,0 @@ -kind: infrastructure/network -version: 0.3.0 -title: "Network Config" -provider: azure -name: default -specification: - some_setting: "setting" diff --git a/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml b/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml new file mode 100644 index 0000000000..1835a6fb3e --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml @@ -0,0 +1,8 @@ +kind: infrastructure/resource-group +version: 0.3.0 +title: "Resource Group" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + region: SET_BY_AUTOMATION \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml new file mode 100644 index 0000000000..b4866fdd3e --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml @@ -0,0 +1,10 @@ +kind: infrastructure/vnet +version: 0.3.0 +title: "VNET Config" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + address_space: SET_BY_AUTOMATION + location: SET_BY_AUTOMATION + resource_group_name: SET_BY_AUTOMATION diff --git a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 index f853cd59dd..faca2beeb6 100644 --- a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 +++ b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 @@ -1,5 +1,5 @@ ##################################################### -# DO NOT Modify by hand - Manage by Automation +# DO NOT Modify by hand - Managed by Automation ##################################################### ##################################################### # This file can be used as a base template to build other Terraform files. It attempts to use as much @@ -12,8 +12,3 @@ provider "azurerm" { } - -resource "azurerm_resource_group" "rg" { - name = "{{ specification.cloud.resource_group_name }}" - location = "{{ specification.cloud.region }}" -} diff --git a/core/src/epicli/data/azure/terraform/infrastructure/net.j2 b/core/src/epicli/data/azure/terraform/infrastructure/net.j2 deleted file mode 100644 index 12bf580733..0000000000 --- a/core/src/epicli/data/azure/terraform/infrastructure/net.j2 +++ /dev/null @@ -1 +0,0 @@ -# TODO: Fill template diff --git a/core/src/epicli/data/azure/terraform/infrastructure/network.j2 b/core/src/epicli/data/azure/terraform/infrastructure/network.j2 deleted file mode 100644 index 98a88ee414..0000000000 --- a/core/src/epicli/data/azure/terraform/infrastructure/network.j2 +++ /dev/null @@ -1,5 +0,0 @@ -##################################################### -# Network - {{ name }} -##################################################### - -# TODO: Fill template diff --git a/core/src/epicli/data/azure/terraform/infrastructure/resource-group.j2 b/core/src/epicli/data/azure/terraform/infrastructure/resource-group.j2 new file mode 100644 index 0000000000..11c6cb870c --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/resource-group.j2 @@ -0,0 +1,17 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + + +resource "azurerm_resource_group" "rg" { + name = "{{ specification.name }}" + location = "{{ specification.region }}" +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 b/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 new file mode 100644 index 0000000000..e4e64f4ad1 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 @@ -0,0 +1,18 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_virtual_network" "vnet" { + name = "{{ specification.name }}" + address_space = ["{{ specification.address_space }}"] + location = "{{ specification.location }}" + resource_group_name = "{{ specification.resource_group_name }}" +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/validation/infrastructure/network.yml b/core/src/epicli/data/azure/validation/infrastructure/resource-group.yml similarity index 100% rename from core/src/epicli/data/azure/validation/infrastructure/network.yml rename to core/src/epicli/data/azure/validation/infrastructure/resource-group.yml diff --git a/core/src/epicli/data/azure/validation/infrastructure/vnet.yml b/core/src/epicli/data/azure/validation/infrastructure/vnet.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/vnet.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 2ecfb928f5..19934a2d31 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -11,7 +11,6 @@ specification: key_path: /root/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH cloud: subscription_name: YOUR-SUB-NAME - resource_group_name: YOUR-RESOURCE-GROUP-NAME vnet_address_pool: 10.1.0.0/20 use_public_ips: False # When not using public IPs you have to provide connectivity via private IPs (VPN) use_service_principal: False From 96e7a7ad7179b60488aeefd900a469a4c9603cd2 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Wed, 14 Aug 2019 16:33:52 +0200 Subject: [PATCH 19/57] Debug improvements (#438) - Simplified error handling by moving it to the root of all CLI paths - Added debug flag to output debug info. (including Terraform and Ansible) - Added auto-approve flag to CLI - Fixed Terraform Azure issue where creating additional resources after resource group would fail because the resource group was not ready jet. - Updated/Improved/Added various unit tests --- core/src/epicli/cli/engine/BuildEngine.py | 62 ++++++++----------- core/src/epicli/cli/engine/DeleteEngine.py | 32 +++++----- core/src/epicli/cli/engine/InitEngine.py | 18 +++--- core/src/epicli/cli/engine/PatchEngine.py | 24 ++----- .../cli/engine/ansible/AnsibleCommand.py | 4 ++ .../providers/azure/InfrastructureBuilder.py | 2 - .../{ => schema}/ConfigurationAppender.py | 0 .../cli/engine/{ => schema}/DefaultMerger.py | 0 .../engine/{ => schema}/SchemaValidator.py | 0 .../cli/engine/terraform/TerraformCommand.py | 4 ++ .../cli/engine/terraform/TerraformRunner.py | 1 - core/src/epicli/cli/epicli.py | 30 ++++++--- core/src/epicli/cli/helpers/Config.py | 20 ++++++ core/src/epicli/cli/helpers/query_yes_no.py | 5 ++ .../azure/defaults/infrastructure/vnet.yml | 2 - .../azure/terraform/infrastructure/vnet.j2 | 4 +- .../providers/aws/test_AWSConfigBuilder.py | 16 +---- .../azure/test_AzureConfigBuilder.py | 40 ++++++++++++ .../tests/cli/helpers/test_name_helpers.py | 32 ++++++++++ .../cli/helpers/test_role_name_helper.py | 8 --- 20 files changed, 185 insertions(+), 119 deletions(-) rename core/src/epicli/cli/engine/{ => schema}/ConfigurationAppender.py (100%) rename core/src/epicli/cli/engine/{ => schema}/DefaultMerger.py (100%) rename core/src/epicli/cli/engine/{ => schema}/SchemaValidator.py (100%) create mode 100644 core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py create mode 100644 core/src/epicli/tests/cli/helpers/test_name_helpers.py delete mode 100644 core/src/epicli/tests/cli/helpers/test_role_name_helper.py diff --git a/core/src/epicli/cli/engine/BuildEngine.py b/core/src/epicli/cli/engine/BuildEngine.py index fd10637c7e..81f9533e03 100644 --- a/core/src/epicli/cli/engine/BuildEngine.py +++ b/core/src/epicli/cli/engine/BuildEngine.py @@ -6,9 +6,9 @@ from cli.helpers.yaml_helpers import safe_load_all from cli.helpers.Log import Log from cli.engine.providers.provider_class_loader import provider_class_loader -from cli.engine.DefaultMerger import DefaultMerger -from cli.engine.SchemaValidator import SchemaValidator -from cli.engine.ConfigurationAppender import ConfigurationAppender +from cli.engine.schema.DefaultMerger import DefaultMerger +from cli.engine.schema.SchemaValidator import SchemaValidator +from cli.engine.schema.ConfigurationAppender import ConfigurationAppender from cli.engine.terraform.TerraformTemplateGenerator import TerraformTemplateGenerator from cli.engine.terraform.TerraformRunner import TerraformRunner from cli.engine.ansible.AnsibleRunner import AnsibleRunner @@ -78,53 +78,45 @@ def collect_infrastructure_config(self): config_collector.run() def validate(self): - try: - self.process_input_docs() + self.process_input_docs() - self.process_configuration_docs() + self.process_configuration_docs() - self.process_infrastructure_docs() + self.process_infrastructure_docs() - save_manifest([*self.input_docs, *self.configuration_docs, *self.infrastructure_docs], self.cluster_model.specification.name) + save_manifest([*self.input_docs, *self.configuration_docs, *self.infrastructure_docs], self.cluster_model.specification.name) - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) #TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + return 0 def apply(self): - try: - self.process_input_docs() + self.process_input_docs() - self.process_infrastructure_docs() + self.process_infrastructure_docs() - if not (self.skip_infrastructure or self.is_provider_any(self.cluster_model)): - # Generate terraform templates - with TerraformTemplateGenerator(self.cluster_model, self.infrastructure_docs) as template_generator: - template_generator.run() + if not (self.skip_infrastructure or self.is_provider_any(self.cluster_model)): + # Generate terraform templates + with TerraformTemplateGenerator(self.cluster_model, self.infrastructure_docs) as template_generator: + template_generator.run() - # Run Terraform to create infrastructure - with TerraformRunner(self.cluster_model, self.configuration_docs) as tf_runner: - tf_runner.build() + # Run Terraform to create infrastructure + with TerraformRunner(self.cluster_model, self.configuration_docs) as tf_runner: + tf_runner.build() - self.process_configuration_docs() + self.process_configuration_docs() - self.collect_infrastructure_config() + self.collect_infrastructure_config() - # Merge all the docs - docs = [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs] + # Merge all the docs + docs = [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs] - # Save docs to manifest file - save_manifest(docs, self.cluster_model.specification.name) + # Save docs to manifest file + save_manifest(docs, self.cluster_model.specification.name) - # Run Ansible to provision infrastructure - with AnsibleRunner(self.cluster_model, docs) as ansible_runner: - ansible_runner.run() + # Run Ansible to provision infrastructure + with AnsibleRunner(self.cluster_model, docs) as ansible_runner: + ansible_runner.run() - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + return 0 def dry_run(self): diff --git a/core/src/epicli/cli/engine/DeleteEngine.py b/core/src/epicli/cli/engine/DeleteEngine.py index 22c094dcb1..1b25b415d4 100644 --- a/core/src/epicli/cli/engine/DeleteEngine.py +++ b/core/src/epicli/cli/engine/DeleteEngine.py @@ -21,23 +21,19 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) def delete(self): - try: - path_to_manifest = os.path.join(self.build_directory, MANIFEST_FILE_NAME) - if not os.path.isfile(path_to_manifest): - raise Exception('No manifest.yml inside the build folder') + path_to_manifest = os.path.join(self.build_directory, MANIFEST_FILE_NAME) + if not os.path.isfile(path_to_manifest): + raise Exception('No manifest.yml inside the build folder') - docs = load_yamls_file(path_to_manifest) - cluster_model = select_single(docs, lambda x: x.kind == 'epiphany-cluster') + docs = load_yamls_file(path_to_manifest) + cluster_model = select_single(docs, lambda x: x.kind == 'epiphany-cluster') + + if cluster_model.provider == 'any': + raise Exception('Delete works only for cloud providers') + + with TerraformRunner(cluster_model, docs) as tf_runner: + tf_runner.delete() - if cluster_model.provider == 'any': - raise Exception('Delete works only for cloud providers') - - with TerraformRunner(cluster_model, docs) as tf_runner: - tf_runner.delete() - - shutil.rmtree(self.build_directory, ignore_errors=True) - - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 \ No newline at end of file + shutil.rmtree(self.build_directory, ignore_errors=True) + + return 0 \ No newline at end of file diff --git a/core/src/epicli/cli/engine/InitEngine.py b/core/src/epicli/cli/engine/InitEngine.py index b054e5090b..a7a94323c2 100644 --- a/core/src/epicli/cli/engine/InitEngine.py +++ b/core/src/epicli/cli/engine/InitEngine.py @@ -23,20 +23,16 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) def init(self): - try: - defaults = load_all_yaml_objs(types.DEFAULT, self.provider, 'configuration/minimal-cluster-config') - defaults[0].specification.name = self.name + defaults = load_all_yaml_objs(types.DEFAULT, self.provider, 'configuration/minimal-cluster-config') + defaults[0].specification.name = self.name - if self.is_full_config: - defaults = self.get_full_config(defaults) + if self.is_full_config: + defaults = self.get_full_config(defaults) - save_manifest(defaults, self.name, self.name+'.yml') + save_manifest(defaults, self.name, self.name+'.yml') - self.logger.info('Initialized user configuration and saved it to "' + os.path.join(get_build_path(self.name), self.name + '.yml') + '"') - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + self.logger.info('Initialized user configuration and saved it to "' + os.path.join(get_build_path(self.name), self.name + '.yml') + '"') + return 0 def get_full_config(self, config_docs): cluster_config_path = save_manifest(config_docs, self.name, self.name + '.yml') diff --git a/core/src/epicli/cli/engine/PatchEngine.py b/core/src/epicli/cli/engine/PatchEngine.py index 086b34fb1d..a183e1c990 100644 --- a/core/src/epicli/cli/engine/PatchEngine.py +++ b/core/src/epicli/cli/engine/PatchEngine.py @@ -21,28 +21,16 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) def upgrade(self): - try: - self.upgrade_patch_files_and_run('upgrade') - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + self.upgrade_patch_files_and_run('upgrade') + return 0 def backup(self): - try: - self.upgrade_patch_files_and_run('backup') - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + self.upgrade_patch_files_and_run('backup') + return 0 def recovery(self): - try: - self.upgrade_patch_files_and_run('recovery') - return 0 - except Exception as e: - self.logger.error(e, exc_info=True) # TODO extensive debug output might not always be wanted. Make this configurable with input flag? - return 1 + self.upgrade_patch_files_and_run('recovery') + return 0 def upgrade_patch_files_and_run(self, action): self.logger.info(f'Running {action}...') diff --git a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py index a0373562b4..6d46fa19d8 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py @@ -1,6 +1,7 @@ import os import subprocess from cli.helpers.Log import LogPipe, Log +from cli.helpers.Config import Config import time @@ -56,6 +57,9 @@ def run_playbook(self, inventory, playbook_path): cmd.append(playbook_path) + if Config().debug: + cmd.append('-vvv') + self.logger.info('Running: "' + ' '.join(cmd) + '"') logpipe = LogPipe(__name__) diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 3f9af30d3f..267fbd4dbe 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -35,8 +35,6 @@ def get_virtual_network(self): vnet = self.get_config_or_default(self.docs, 'infrastructure/vnet') vnet.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vnet') vnet.specification.address_space = self.cluster_model.specification.cloud.vnet_address_pool - vnet.specification.resource_group_name = self.resource_group_name - vnet.specification.location = self.cluster_model.specification.cloud.region return vnet @staticmethod diff --git a/core/src/epicli/cli/engine/ConfigurationAppender.py b/core/src/epicli/cli/engine/schema/ConfigurationAppender.py similarity index 100% rename from core/src/epicli/cli/engine/ConfigurationAppender.py rename to core/src/epicli/cli/engine/schema/ConfigurationAppender.py diff --git a/core/src/epicli/cli/engine/DefaultMerger.py b/core/src/epicli/cli/engine/schema/DefaultMerger.py similarity index 100% rename from core/src/epicli/cli/engine/DefaultMerger.py rename to core/src/epicli/cli/engine/schema/DefaultMerger.py diff --git a/core/src/epicli/cli/engine/SchemaValidator.py b/core/src/epicli/cli/engine/schema/SchemaValidator.py similarity index 100% rename from core/src/epicli/cli/engine/SchemaValidator.py rename to core/src/epicli/cli/engine/schema/SchemaValidator.py diff --git a/core/src/epicli/cli/engine/terraform/TerraformCommand.py b/core/src/epicli/cli/engine/terraform/TerraformCommand.py index 1e09502638..d04fb09b73 100644 --- a/core/src/epicli/cli/engine/terraform/TerraformCommand.py +++ b/core/src/epicli/cli/engine/terraform/TerraformCommand.py @@ -1,6 +1,7 @@ import os import subprocess from cli.helpers.Log import LogPipe, Log +from cli.helpers.Config import Config class TerraformCommand: @@ -40,6 +41,9 @@ def run(self, command, env, auto_approve=False): cmd = ' '.join(cmd) self.logger.info(f'Running: "{cmd}"') + if Config().debug: + env['TF_LOG'] = 'TRACE' + logpipe = LogPipe(__name__) with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe, env=env, shell=True) as sp: logpipe.close() diff --git a/core/src/epicli/cli/engine/terraform/TerraformRunner.py b/core/src/epicli/cli/engine/terraform/TerraformRunner.py index c379367f5c..02b1784499 100644 --- a/core/src/epicli/cli/engine/terraform/TerraformRunner.py +++ b/core/src/epicli/cli/engine/terraform/TerraformRunner.py @@ -6,7 +6,6 @@ from cli.helpers.data_loader import load_yaml_file from cli.helpers.naming_helpers import resource_name - class TerraformRunner(Step): def __init__(self, cluster_model, config_docs): diff --git a/core/src/epicli/cli/epicli.py b/core/src/epicli/cli/epicli.py index 5492a742c5..c8ad612acf 100644 --- a/core/src/epicli/cli/epicli.py +++ b/core/src/epicli/cli/epicli.py @@ -28,20 +28,24 @@ def main(): parser.add_argument('--licenses', action='version', help='Shows the third party packages and their licenses the CLI is using.', version=json.dumps(LICENSES, indent=4)) - parser.add_argument('-l', '--log_file', dest='log_name', type=str, + parser.add_argument('-l', '--log-file', dest='log_name', type=str, help='The name of the log file written to the output directory') - parser.add_argument('--log_format', dest='log_format', type=str, + parser.add_argument('--log-format', dest='log_format', type=str, help='Format for the logging string.') - parser.add_argument('--log_date_format', dest='log_date_format', type=str, + parser.add_argument('--log-date-format', dest='log_date_format', type=str, help='Format for the logging date.') - parser.add_argument('--log_count', dest='log_count', type=str, + parser.add_argument('--log-count', dest='log_count', type=str, help='Roleover count where each CLI run will generate a new log.') - parser.add_argument('--log_type', choices=['plain', 'json'], default='plain', + parser.add_argument('--log-type', choices=['plain', 'json'], default='plain', dest='log_type', action='store', help='Type of logs.') - parser.add_argument('--validate_certs', choices=['true', 'false'], default='true', action='store', dest='validate_certs', + parser.add_argument('--validate-certs', choices=['true', 'false'], default='true', action='store', dest='validate_certs', help='''[Experimental]: Disables certificate checks for certain Ansible operations which might have issues behind proxies (https://github.com/ansible/ansible/issues/32750). Should NOT be used in production for security reasons.''') + parser.add_argument('--debug', dest='debug', action="store_true", + help='Set this to output extensive debug information. Carries over to Ansible and Terraform.') + parser.add_argument('--auto-approve', dest='auto_approve', action="store_true", + help='Auto approve any user input queries asked by Epicli') # some arguments we don't want available when running from the docker image. if not config.docker_cli: parser.add_argument('-o', '--output', dest='output_dir', type=str, @@ -74,9 +78,15 @@ def main(): config.log_type = args.log_type config.log_count = args.log_count config.validate_certs = True if args.validate_certs == 'true' else False + config.debug = args.debug + config.auto_approve = args.auto_approve - return args.func(args) - + try: + return args.func(args) + except Exception as e: + logger = Log('epicli') + logger.error(e, exc_info=config.debug) + return 1 def init_parser(subparsers): sub_parser = subparsers.add_parser('init', description='Creates configuration file in working directory.') @@ -84,12 +94,12 @@ def init_parser(subparsers): required=True, help='One of the supported providers: azure|aws|any') sub_parser.add_argument('-n', '--name', dest='name', type=str, required=True, help='Name of the cluster.') - sub_parser.add_argument('--full', dest='full_config', action="store_true", help='Use this flag if you want to create verbose configuration file.') def run_init(args): Config().output_dir = os.getcwd() + dump_config(Config()) with InitEngine(args) as engine: return engine.init() @@ -193,6 +203,7 @@ def adjust_paths_from_file(args): if not os.path.isabs(args.file): args.file = os.path.join(os.getcwd(), args.file) if not os.path.isfile(args.file): + Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. raise Exception(f'File "{args.file}" does not excist') if Config().output_dir is None: Config().output_dir = os.path.join(os.path.dirname(args.file), 'build') @@ -203,6 +214,7 @@ def adjust_paths_from_build(args): if not os.path.isabs(args.build_directory): args.build_directory = os.path.join(os.getcwd(), args.build_directory) if not os.path.exists(args.build_directory): + Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. raise Exception(f'Build directory "{args.build_directory}" does not excist') if args.build_directory[-1:] == '/': args.build_directory = args.build_directory.rstrip('/') diff --git a/core/src/epicli/cli/helpers/Config.py b/core/src/epicli/cli/helpers/Config.py index 36379c6bd2..5bd6583e35 100644 --- a/core/src/epicli/cli/helpers/Config.py +++ b/core/src/epicli/cli/helpers/Config.py @@ -16,6 +16,8 @@ def __init__(self): self._log_type = 'plain' self._validate_certs = True + self._debug = False + self._auto_approve = False @property def docker_cli(self): @@ -84,6 +86,24 @@ def validate_certs(self, validate_certs): if not validate_certs is None: self._validate_certs = validate_certs + @property + def debug(self): + return self._debug + + @debug.setter + def debug(self, debug): + if not debug is None: + self._debug = debug + + @property + def auto_approve(self): + return self._auto_approve + + @auto_approve.setter + def auto_approve(self, auto_approve): + if not auto_approve is None: + self._auto_approve = auto_approve + instance = None def __new__(cls): diff --git a/core/src/epicli/cli/helpers/query_yes_no.py b/core/src/epicli/cli/helpers/query_yes_no.py index 46e5069db8..f6982c3f23 100644 --- a/core/src/epicli/cli/helpers/query_yes_no.py +++ b/core/src/epicli/cli/helpers/query_yes_no.py @@ -1,7 +1,12 @@ import sys +from cli.helpers.Config import Config + def query_yes_no(question, default="yes"): + if Config().auto_approve: + return True + valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} if default is None: diff --git a/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml index b4866fdd3e..edefde5dc1 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml @@ -6,5 +6,3 @@ name: default specification: name: SET_BY_AUTOMATION address_space: SET_BY_AUTOMATION - location: SET_BY_AUTOMATION - resource_group_name: SET_BY_AUTOMATION diff --git a/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 b/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 index e4e64f4ad1..abff872133 100644 --- a/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 +++ b/core/src/epicli/data/azure/terraform/infrastructure/vnet.j2 @@ -13,6 +13,6 @@ resource "azurerm_virtual_network" "vnet" { name = "{{ specification.name }}" address_space = ["{{ specification.address_space }}"] - location = "{{ specification.location }}" - resource_group_name = "{{ specification.resource_group_name }}" + resource_group_name = "${azurerm_resource_group.rg.name}" + location = "${azurerm_resource_group.rg.location}" } \ No newline at end of file diff --git a/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py index bd6c8044f4..e3fd23f37c 100644 --- a/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/aws/test_AWSConfigBuilder.py @@ -2,24 +2,14 @@ from cli.helpers.objdict_helpers import dict_to_objdict import pytest - -def test_get_vpc_config_should_set_address_pool_from_cluster_data_model(): - cluster_model = get_cluster_model(address_pool='10.20.0.0/22') - builder = InfrastructureBuilder([cluster_model]) - - actual = builder.get_vpc_config() - - assert actual.specification.address_pool == '10.20.0.0/22' - - -def test_get_vpc_config_should_set_name_from_cluster_data_model(): - cluster_model = get_cluster_model(cluster_name='TestCluster') +def test_get_vpc_config_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster', address_pool='10.20.0.0/22') builder = InfrastructureBuilder([cluster_model]) actual = builder.get_vpc_config() assert actual.specification.name == 'prefix-testcluster-vpc' - + assert actual.specification.address_pool == '10.20.0.0/22' def test_get_subnet_config_should_set_proper_values_to_model(): cluster_model = get_cluster_model(cluster_name='TestCluster') diff --git a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py new file mode 100644 index 0000000000..a014fd6b87 --- /dev/null +++ b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py @@ -0,0 +1,40 @@ +from cli.engine.providers.azure.InfrastructureBuilder import InfrastructureBuilder +from cli.helpers.objdict_helpers import dict_to_objdict +import pytest + + +def test_get_resource_group_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_resource_group() + + assert actual.specification.name == 'prefix-testcluster-rg' + assert actual.specification.region == 'West Europe' + + +def test_get_virtual_network_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_virtual_network() + + assert actual.specification.name == 'prefix-testcluster-vnet' + assert actual.specification.address_space == '10.22.0.0/22' + + +def get_cluster_model(address_pool='10.22.0.0/22', cluster_name='EpiphanyTestCluster'): + cluster_model = dict_to_objdict({ + 'kind': 'epiphany-cluster', + 'provider': 'azure', + 'specification': { + 'name': cluster_name, + 'prefix': 'prefix', + 'cloud': { + 'region': 'West Europe', + 'vnet_address_pool': address_pool + } + } + }) + return cluster_model + diff --git a/core/src/epicli/tests/cli/helpers/test_name_helpers.py b/core/src/epicli/tests/cli/helpers/test_name_helpers.py new file mode 100644 index 0000000000..33fe6c6ac7 --- /dev/null +++ b/core/src/epicli/tests/cli/helpers/test_name_helpers.py @@ -0,0 +1,32 @@ +from cli.helpers.naming_helpers import to_role_name, to_feature_name, resource_name + + +def test_to_role_name(): + actual = to_role_name("infrastructure/route-table-association") + assert actual == "infrastructure/route_table_association" + + +def test_to_feature_name(): + actual = to_feature_name("route_table_association") + assert actual == "route-table-association" + + +def test_resource_name_cn_rt(): + actual = resource_name('default', 'Cluster', 'Type') + assert actual == "cluster-type" + + +def test_resource_name_pr_cn_rt(): + actual = resource_name('prefix', 'Cluster', 'Type') + assert actual == "prefix-cluster-type" + + +def test_resource_name_cn_rt_cmp(): + actual = resource_name('default', 'Cluster', 'Type', component='Component') + assert actual == "cluster-component-type" + + +def test_resource_name_pr_cn_rt_cmp(): + actual = resource_name('prefix', 'Cluster', 'Type', component='Component') + assert actual == "prefix-cluster-component-type" + diff --git a/core/src/epicli/tests/cli/helpers/test_role_name_helper.py b/core/src/epicli/tests/cli/helpers/test_role_name_helper.py deleted file mode 100644 index 344c660fb6..0000000000 --- a/core/src/epicli/tests/cli/helpers/test_role_name_helper.py +++ /dev/null @@ -1,8 +0,0 @@ -from cli.helpers.naming_helpers import to_role_name - - -def test_replaces_all_hyphens_in_variable(): - - actual = to_role_name("infrastructure/route-table-association") - - assert actual == "infrastructure/route_table_association" From 7e67c748b5714059bc30e1edc17320060b1cdf18 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Fri, 16 Aug 2019 08:31:45 +0200 Subject: [PATCH 20/57] HAProxy and Prometheus test fixes (#435) * Removing the test environment destruction function * HAProxy and Prometheus test fixes --- .../haproxy_tls_termination_spec.rb | 14 ++++--- .../spec/grafana/grafana_spec.rb | 2 +- .../spec/haproxy/haproxy_spec.rb | 23 +++++++++--- .../spec/prometheus/prometheus_spec.rb | 37 ++++++++++--------- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/core/core/test/serverspec/spec/haproxy_tls_termination/haproxy_tls_termination_spec.rb b/core/core/test/serverspec/spec/haproxy_tls_termination/haproxy_tls_termination_spec.rb index ff5b3bb773..095aab54d4 100644 --- a/core/core/test/serverspec/spec/haproxy_tls_termination/haproxy_tls_termination_spec.rb +++ b/core/core/test/serverspec/spec/haproxy_tls_termination/haproxy_tls_termination_spec.rb @@ -2,6 +2,7 @@ haproxy_host = 'localhost' haproxy_front_port = 443 +haproxy_stats_port = 9000 describe 'Checking if HAProxy service is running' do describe service('haproxy') do @@ -32,8 +33,11 @@ end describe 'Checking if the ports are open' do + let(:disable_sudo) { false } describe port(haproxy_front_port) do - let(:disable_sudo) { false } + it { should be_listening } + end + describe port(haproxy_stats_port) do it { should be_listening } end end @@ -71,14 +75,14 @@ end describe 'Checking HAProxy HTTP status code for stats page' do - describe command("curl -k --user $(cat /etc/haproxy/haproxy.cfg | grep 'stats auth' | awk '{print $3}') -o /dev/null -s -w '%{http_code}' \ - https://#{haproxy_host}:#{haproxy_front_port}$(cat /etc/haproxy/haproxy.cfg | grep 'stats uri' | awk '{print $3}')") do + describe command("curl -k --user $(awk '/stats auth/ {print $3}' /etc/haproxy/haproxy.cfg) -o /dev/null -s -w '%{http_code}' \ + http://#{haproxy_host}:#{haproxy_stats_port}$(awk '/stats uri/ {print $3}' /etc/haproxy/haproxy.cfg)") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end end - describe command("curl -k --user $(cat /etc/haproxy/haproxy.cfg | grep 'stats auth' | awk '{print $3}') \ - https://#{haproxy_host}:#{haproxy_front_port}$(cat /etc/haproxy/haproxy.cfg | grep 'stats uri' | awk '{print $3}')") do + describe command("curl -k --user $(awk '/stats auth/ {print $3}' /etc/haproxy/haproxy.cfg) \ + http://#{haproxy_host}:#{haproxy_stats_port}$(awk '/stats uri/ {print $3}' /etc/haproxy/haproxy.cfg)") do its(:stdout) { should match /Statistics Report for HAProxy/ } end end diff --git a/core/src/epicli/tests/serverspec-cli/spec/grafana/grafana_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/grafana/grafana_spec.rb index 91a701b2a9..642c1adad7 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/grafana/grafana_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/grafana/grafana_spec.rb @@ -31,7 +31,7 @@ it { should exist } it { should be_a_directory } it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } + it { should be_grouped_into 'grafana' } end describe file("/etc/grafana/grafana.ini") do it { should exist } diff --git a/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb index ff5b3bb773..cabc64bf82 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb @@ -2,6 +2,16 @@ haproxy_host = 'localhost' haproxy_front_port = 443 +haproxy_stats_port = 9000 + +# Running systemctl status command as "is-active" returns "unknown" in result +# https://bugzilla.redhat.com/show_bug.cgi?id=1073481 + +describe 'Checking HAProxy service status' do + describe command("systemctl status haproxy") do + its(:exit_status) { should eq 0 } + end +end describe 'Checking if HAProxy service is running' do describe service('haproxy') do @@ -32,8 +42,11 @@ end describe 'Checking if the ports are open' do + let(:disable_sudo) { false } describe port(haproxy_front_port) do - let(:disable_sudo) { false } + it { should be_listening } + end + describe port(haproxy_stats_port) do it { should be_listening } end end @@ -71,14 +84,14 @@ end describe 'Checking HAProxy HTTP status code for stats page' do - describe command("curl -k --user $(cat /etc/haproxy/haproxy.cfg | grep 'stats auth' | awk '{print $3}') -o /dev/null -s -w '%{http_code}' \ - https://#{haproxy_host}:#{haproxy_front_port}$(cat /etc/haproxy/haproxy.cfg | grep 'stats uri' | awk '{print $3}')") do + describe command("curl -k --user $(awk '/stats auth/ {print $3}' /etc/haproxy/haproxy.cfg) -o /dev/null -s -w '%{http_code}' \ + http://#{haproxy_host}:#{haproxy_stats_port}$(awk '/stats uri/ {print $3}' /etc/haproxy/haproxy.cfg)") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end end - describe command("curl -k --user $(cat /etc/haproxy/haproxy.cfg | grep 'stats auth' | awk '{print $3}') \ - https://#{haproxy_host}:#{haproxy_front_port}$(cat /etc/haproxy/haproxy.cfg | grep 'stats uri' | awk '{print $3}')") do + describe command("curl -k --user $(awk '/stats auth/ {print $3}' /etc/haproxy/haproxy.cfg) \ + http://#{haproxy_host}:#{haproxy_stats_port}$(awk '/stats uri/ {print $3}' /etc/haproxy/haproxy.cfg)") do its(:stdout) { should match /Statistics Report for HAProxy/ } end end diff --git a/core/src/epicli/tests/serverspec-cli/spec/prometheus/prometheus_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/prometheus/prometheus_spec.rb index 460983475d..da685c99e7 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/prometheus/prometheus_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/prometheus/prometheus_spec.rb @@ -5,6 +5,7 @@ kube_apiserver_secure_port = 6443 alertmanager_host = 'localhost' alertmanager_port = 9093 +kubelet_port = 10250 describe 'Checking if Prometheus user exists' do describe group('prometheus') do @@ -110,7 +111,7 @@ describe 'Checking connection to HAProxy Exporter hosts' do listInventoryHosts("haproxy_exporter").each do |val| let(:disable_sudo) { false } - describe command("curl -o /dev/null -s -w '%{http_code}' $(grep -oP \"(?<=targets: \\\[\\\").*(?=\\\"\\\])\" /etc/prometheus/file_sd/haproxy-exporter-#{val}.yml)/metrics") do + describe command("curl -o /dev/null -s -w '%{http_code}' $(grep -oP \"(?<=targets: \\\[\').*(?=\'\\\])\" /etc/prometheus/file_sd/haproxy-exporter-#{val}.yml)/metrics") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end @@ -168,7 +169,7 @@ listInventoryHosts("kubernetes_master").each do |val| let(:disable_sudo) { false } describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-apiservers /etc/prometheus/prometheus.yml \ - | awk '/bearer_token/ {print $2}')\" https://#{val}:#{kube_apiserver_secure_port}/metrics") do + | awk '/bearer_token/ {print $2}' | tr -d '\"')\" https://#{val}:#{kube_apiserver_secure_port}/metrics") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end @@ -180,40 +181,40 @@ let(:disable_sudo) { false } listInventoryHosts("kubernetes_master").each do |val_m| describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-cadvisor /etc/prometheus/prometheus.yml \ - | awk '/bearer_token/ {print $2}')\" https://#{val_m}:#{kube_apiserver_secure_port}/api/v1/nodes/#{val_m}/proxy/metrics/cadvisor") do + | awk '/bearer_token/ {print $2}' | tr -d '\"')\" https://#{val_m}:#{kubelet_port}/metrics/cadvisor") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end end - listInventoryHosts("kubernetes_node").each do |val_w| - describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-cadvisor /etc/prometheus/prometheus.yml \ - | awk '/bearer_token/ {print $2}')\" https://#{val_m}:#{kube_apiserver_secure_port}/api/v1/nodes/#{val_w}/proxy/metrics/cadvisor") do - it "is expected to be equal" do - expect(subject.stdout.to_i).to eq 200 - end + end + listInventoryHosts("kubernetes_node").each do |val_w| + describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-cadvisor /etc/prometheus/prometheus.yml \ + | awk '/bearer_token/ {print $2}' | tr -d '\"')\" https://#{val_w}:#{kubelet_port}/metrics/cadvisor") do + it "is expected to be equal" do + expect(subject.stdout.to_i).to eq 200 end end - end + end end describe 'Checking connection to Kubernetes nodes' do let(:disable_sudo) { false } listInventoryHosts("kubernetes_master").each do |val_m| describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-nodes /etc/prometheus/prometheus.yml \ - | awk '/bearer_token/ {print $2}')\" https://#{val_m}:#{kube_apiserver_secure_port}/api/v1/nodes/#{val_m}/proxy/metrics") do + | awk '/bearer_token/ {print $2}' | tr -d '\"')\" https://#{val_m}:#{kubelet_port}/metrics") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 end end - listInventoryHosts("kubernetes_node").each do |val_w| - describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-nodes /etc/prometheus/prometheus.yml \ - | awk '/bearer_token/ {print $2}')\" https://#{val_m}:#{kube_apiserver_secure_port}/api/v1/nodes/#{val_w}/proxy/metrics") do - it "is expected to be equal" do - expect(subject.stdout.to_i).to eq 200 - end + end + listInventoryHosts("kubernetes_node").each do |val_w| + describe command("curl -o /dev/null -s -w '%{http_code}' -k -H \"Authorization: Bearer $(grep -A 6 kubernetes-nodes /etc/prometheus/prometheus.yml \ + | awk '/bearer_token/ {print $2}' | tr -d '\"')\" https://#{val_w}:#{kubelet_port}/metrics") do + it "is expected to be equal" do + expect(subject.stdout.to_i).to eq 200 end end - end + end end From 6c919a7d2bc1ad87d3e807b954e3ed05d9517b5e Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Mon, 26 Aug 2019 12:13:37 +0200 Subject: [PATCH 21/57] Feature/development-docs (#439) * Updating documentation for development environment --- README.md | 17 +- core/src/epicli/.vscode/extensions.json | 4 +- core/src/epicli/tests/{ => cli}/conftest.py | 0 docs/assets/images/development/building.png | 3 + docs/assets/images/development/debug.png | 3 + .../images/development/devcontainer.png | 3 + docs/assets/images/development/extensions.png | 3 + docs/assets/images/development/rundebug.png | 3 + docs/assets/images/development/terminal.png | 3 + docs/assets/images/development/unittests.png | 3 + docs/home/CONTRIBUTING.md | 42 ----- docs/home/DEVELOPMENT.md | 145 ++++++++++++++++++ docs/home/GOVERNANCE.md | 8 - docs/home/HOWTO.md | 16 -- 14 files changed, 178 insertions(+), 75 deletions(-) rename core/src/epicli/tests/{ => cli}/conftest.py (100%) create mode 100644 docs/assets/images/development/building.png create mode 100644 docs/assets/images/development/debug.png create mode 100644 docs/assets/images/development/devcontainer.png create mode 100644 docs/assets/images/development/extensions.png create mode 100644 docs/assets/images/development/rundebug.png create mode 100644 docs/assets/images/development/terminal.png create mode 100644 docs/assets/images/development/unittests.png delete mode 100644 docs/home/CONTRIBUTING.md create mode 100644 docs/home/DEVELOPMENT.md diff --git a/README.md b/README.md index 0165763cf7..78739fa2fb 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This minimum file definition is fine to start with, if you need more control ove epicli init -p aws -n demo --full ``` -You will need to modify a few values (like you AWS secrets, directory path for ssh keys). Once you are done done with `demo.yaml` you can start cluster deployment by executing with: +You will need to modify a few values (like your AWS secrets, directory path for SSH keys). Once you are done with `demo.yaml` you can start cluster deployment by executing: ```shell epicli apply -f demo.yaml @@ -73,16 +73,17 @@ Find more information using table of contents below - especially the [How-to gui - Platform - [Resources](docs/home/RESOURCES.md) - [How-to guides](docs/home/HOWTO.md) - - [Troubleshooting](docs/home/TROUBLESHOOTING.md) + - [Components](docs/home/COMPONENTS.md) + - [Security](docs/home/SECURITY.md) + - [Troubleshooting](docs/home/TROUBLESHOOTING.md) + - [Changelog](CHANGELOG.md) - Architecture - [Logical View](docs/architecture/logical-view.md) - [Process View](docs/architecture/process-view.md) - [Physical View](docs/architecture/physical-view.md) -- Project - - [How-to contribute](docs/home/CONTRIBUTING.md) - - [Workflow to follow](docs/home/GITWORKFLOW.md) +- Contributing - [Governance model](docs/home/GOVERNANCE.md) - - [Components](docs/home/COMPONENTS.md) - - [Changelog](CHANGELOG.md) - + - [Development environment](docs/home/DEVELOPMENT.md) + - [GIT Workflow](docs/home/GITWORKFLOW.md) + diff --git a/core/src/epicli/.vscode/extensions.json b/core/src/epicli/.vscode/extensions.json index 7223083e1e..0a7a525d2f 100644 --- a/core/src/epicli/.vscode/extensions.json +++ b/core/src/epicli/.vscode/extensions.json @@ -5,6 +5,8 @@ "littlefoxteam.vscode-python-test-adapter", "vscoss.vscode-ansible", "wholroyd.jinja", - "redhat.vscode-yaml" + "redhat.vscode-yaml", + "mauve.terraform", + "davidanson.vscode-markdownlint" ] } \ No newline at end of file diff --git a/core/src/epicli/tests/conftest.py b/core/src/epicli/tests/cli/conftest.py similarity index 100% rename from core/src/epicli/tests/conftest.py rename to core/src/epicli/tests/cli/conftest.py diff --git a/docs/assets/images/development/building.png b/docs/assets/images/development/building.png new file mode 100644 index 0000000000..7b1b402d3c --- /dev/null +++ b/docs/assets/images/development/building.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37624351448d5e8ee126e10184a111399f0c18008a333d2ecc985505dfea152d +size 3832 diff --git a/docs/assets/images/development/debug.png b/docs/assets/images/development/debug.png new file mode 100644 index 0000000000..4bf30b99cf --- /dev/null +++ b/docs/assets/images/development/debug.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70d08d0a9356eefd910e19192d317132dc245f291547e34021594418ed5a91b8 +size 6443 diff --git a/docs/assets/images/development/devcontainer.png b/docs/assets/images/development/devcontainer.png new file mode 100644 index 0000000000..98685d30b1 --- /dev/null +++ b/docs/assets/images/development/devcontainer.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b76c2ecee8ea9141ebc8d7b7f5159b1d35ec71d341f43f7b7ad75180a6a890f7 +size 9057 diff --git a/docs/assets/images/development/extensions.png b/docs/assets/images/development/extensions.png new file mode 100644 index 0000000000..f04738a618 --- /dev/null +++ b/docs/assets/images/development/extensions.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acfd104ce9a484cb1d0b7adee8f24b0465fa3d0be80a21051cae8f8cea010a20 +size 6558 diff --git a/docs/assets/images/development/rundebug.png b/docs/assets/images/development/rundebug.png new file mode 100644 index 0000000000..f20810d496 --- /dev/null +++ b/docs/assets/images/development/rundebug.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c57734ad4a97465a0466cdbd5ef9385c515c20882eba9611de36ee537cebc379 +size 1875 diff --git a/docs/assets/images/development/terminal.png b/docs/assets/images/development/terminal.png new file mode 100644 index 0000000000..c99221fe4c --- /dev/null +++ b/docs/assets/images/development/terminal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5af499a5d8fa9b0851761c21c9826295de8ea439297ddea9e73f01b1df83f4a3 +size 6917 diff --git a/docs/assets/images/development/unittests.png b/docs/assets/images/development/unittests.png new file mode 100644 index 0000000000..1cfdd4a5eb --- /dev/null +++ b/docs/assets/images/development/unittests.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d5ca3e3256014170dab9321d0ae61342248fb5ecc1bbc1c16b905c8e12885aa +size 30168 diff --git a/docs/home/CONTRIBUTING.md b/docs/home/CONTRIBUTING.md deleted file mode 100644 index 86069b1933..0000000000 --- a/docs/home/CONTRIBUTING.md +++ /dev/null @@ -1,42 +0,0 @@ -# Contributing - - - -- [Contributing](#contributing) - - [Welcome](#welcome) - - [Workflow](#workflow) - - [Security](#security) - - [Group/Project Layouts](#group-project-layouts) - - - -## Welcome - -All contributions are welcomed! Contributions can be anything including adding a bug issue. Anything that contributes in any way to Epiphany is considered a contribution and is welcomed. - -## Workflow - TBD - -## Security - -Security *must* be built-in from day one on any merge request. Meaning, all changes must be able to pass security checks and that you have made sure not to include any hardcoded values such as keys, IDs, passwords, etc. By default it establishes perimeter security via firewall rules, IPTables, etc. but it also incorporates cross platform Kubernetes Secrets. Security enhancements will always be addressed. Epiphany will always comply with MCSR. - -## Group/Project Layouts - -Epiphany is broken into a hierarchy with `epiphany-platform` as a group in GitHub that contains folders such as `core`, `docs`, etc. Of course, you can use whatever IDE/editor you like but a good one for this is `Visual Studio Code`. It's based on the same foundation as `Atom` but seems to have more options and when dealing with Azure, it's actually easier. - -```text - -# Create a folder called epiphany -mkdir epiphany -cd epiphany - -# Git clone each project in the epiphany group -git clone git@github.com/epiphany-platform/epiphany.git - -# Folders inside epiphany-platform repository: -# core - Base core of Epiphany. -# data - Data.yaml files that define Epiphany clusters. -# docs - Epiphany platform documentation. -# examples - Examples of how to configure an Epiphany environment, add an application to the Epiphany platform, etc. - -``` diff --git a/docs/home/DEVELOPMENT.md b/docs/home/DEVELOPMENT.md new file mode 100644 index 0000000000..07bdb53a53 --- /dev/null +++ b/docs/home/DEVELOPMENT.md @@ -0,0 +1,145 @@ +# Development + + + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Preparing the environment](#preparing-the-environment) +- [Supplying data to the devcontainer](#supplying-data-to-the-devcontainer) +- [Note for Windows users](#note-for-Windows-users) +- [Running and debugging](#running-and-debugging) +- [Running unit tests](#running-unit-tests) + + + +## Introduction + +This document explains how to set up the preferred [VSCode](https://code.visualstudio.com/) development environment. While there are other options to develop Epiphany like [PyCharm](https://www.jetbrains.com/pycharm/), VSCode has the following advantages: + +1. Epiphany is developed using many different technologies (Python, Ansible, Terraform, Docker, Jinja, YAML...) and VSCode has good tooling and extensions available to support everything in one IDE. + +2. VSCode's [devcontainers](https://code.visualstudio.com/docs/remote/containers) allow us to quickly set up a dockerized development environment, which is the same for every developer regardless of development platform (Linux, MacOS, Windows). + +## Prerequisites + +- [VSCode](https://code.visualstudio.com/) +- Docker-CE + - [Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows) + - [MacOS](https://hub.docker.com/editions/community/docker-ce-desktop-mac) + - [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu/) + +Note: VSCode devcontainers are not properly supported using Docker Toolbox on Windows. More info [here](https://github.com/microsoft/vscode-remote-release/issues/95). + +## Preparing the environment + +1. Open the epicli project folder ```/epiphany/core/src/epicli/``` with VSCode. + +2. VSCode will tell you that the workspace has recommended extensions: + + ![extensions](../assets/images/development/extensions.png) + + Press ```Install All``` and wait until they are all installed and then restart. During the extension installations the following popup might show up: + + ![devcontainer](../assets/images/development/devcontainer.png) + + Do **NOT** do that at this point. First you must restart VSCode to activate all extensions which were installed. + +3. After restarting VSCode the popup to re-open the folder in a devcontainer will show again. Press ```Reopen in Container``` to start the build of the devcontainer. You should get the following message: + + ![building](../assets/images/development/building.png) + + You can click ```details``` to show the build process. + +4. After the devcontainer is built and started, VSCode will show you the message again that this workspace has recommended extensions. This time it is for the devcontainer. Again, press ```Install All``` to install the available extensions inside the devcontainer. + +Now you have a fully working Epiphany development environment! + +## Supplying data to the devcontainer + +The entire working directory (```/epiphany/core/src/epicli/```) is mounted inside the container. We recommend to create an additional directory called ```clusters``` there, in which you house your data YAMLs and SSH keys. This directory is already added to the .gitignore. When executing epicli commands from that directory this is also where any build output and logs are written to. + +## Note for Windows users + +- Watch out for line endings conversion. By default GIT for Windows sets `core.autocrlf=true`. Mounting such files with Docker results in `^M` end-of-line character in the config files. +Use: [Checkout as-is, commit Unix-style](https://stackoverflow.com/questions/10418975/how-to-change-line-ending-settings) (`core.autocrlf=input`) or Checkout as-is, commit as-is (`core.autocrlf=false`). + +- Mounting NTFS disk folders in a Linux based image causes permission issues with SSH keys. You can copy them inside the container and set the proper permissions using: + + ```shell + mkdir -p /home/vscode/.ssh + cp ./clusters/ssh/id_rsa* /home/vscode/.ssh/ + chmod 700 /home/vscode/.ssh && chmod 644 /home/vscode/.ssh/id_rsa.pub && chmod 600 /home/vscode/.ssh/id_rsa + ``` + +This needs to be executed from the devcontainer bash terminal: + +![terminal](../assets/images/development/terminal.png) + +## Running and debugging + +For debugging, open the VSCode's Debug tab: + +![debug](../assets/images/development/debug.png) + +By default there is one launch configuration called ```epicli```. This launch configuration can be found in ```/epiphany/core/src/epicli/.vscode/``` and looks like this: + + ```json + "configurations": [ + { + "name": "epicli", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + } + ] + ``` + +You can copy this configuration and change values (like below) to create different ones to suite your needs: + + ```json + "configurations": [ + { + "name": "epicli", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + }, + { + "name": "epicli show version", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["--version"] + } + ] + ``` + +In the ```args``` field you can pass an array of the arguments that you want epicli to run with. + +To run a configuration, select it and press the run button: + +![rundebug](../assets/images/development/rundebug.png) + +For more information about debugging in VSCode, go [here](https://code.visualstudio.com/docs/editor/debugging). + +## Running unit tests + +The standard Python test runner fails to discover the tests so we use the ```Python Test Explorer``` extension. To run the unit tests, open the VSCode's Test tab and press the run button: + +![unittests](../assets/images/development/unittests.png) + +See the [Python Test Explorer](https://marketplace.visualstudio.com/items?itemName=LittleFoxTeam.vscode-python-test-adapter) extension page on how to debug and run individual tests. diff --git a/docs/home/GOVERNANCE.md b/docs/home/GOVERNANCE.md index 57cb983337..4da49e1b7e 100644 --- a/docs/home/GOVERNANCE.md +++ b/docs/home/GOVERNANCE.md @@ -11,7 +11,6 @@ - [Support](#support) - [Contribution Process](#contribution-process) - [Decision-Making Process](#decision-making-process) - - [Git Workflow and Contributing](#git-workflow-and-contributing) @@ -77,10 +76,3 @@ The developer mailing list is the most appropriate place for a contributor to as ## Decision-Making Process The project leadership model does not need a formal conflict resolution process, since the project lead’s word is final. If the community chooses to question the wisdom of the actions of a committer, the project lead can review their decisions by checking the email archives, and either uphold or reverse them. - -## Git Workflow and Contributing - -These two documents go into detail on how to contribute and work within the branching strategy used by Epiphany: - -* [Gitworkflow.md](/GITWORKFLOW.md) -* [Contributing.md](/CONTRIBUTING.md) diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index 090512e661..41720f3a3c 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -6,7 +6,6 @@ - [Epicli](#epicli) - [Run Epicli directly from OS](#run-epicli-directly-from-os) - [Run Epicli from Docker image](#run-epicli-from-docker-image) - - [Epicli development](#epicli-development) - [Legacy](#legacy) - [Run directly from OS](#run-directly-from-os) - [Run Docker image for development](#run-docker-image-for-development) @@ -157,21 +156,6 @@ docker run -it -v LOCAL_DIR:/shared --rm epiphanyplatform/epicli Where `LOCAL_DIR` should be replaced with the local path to the directory for Epicli input (SSH keys, data yamls) and output (logs, build states). -#### Epicli development - -To setup a development environment to debug or contribute to Epicli follow the following steps. - -1. Install the following dependencies: - - - Python 3.7 - - PIP - - Pipenv - - PyCharm CE - -2. Open PyCharm CE and open the Epicli project root directory `/core/src/epicli`. PyCharm will detect the Pipenv virtual workspace and configure it appropriately. - -Then you can code and debug as desired:) - ### Legacy #### Run directly from OS From d5b20ee90f92de51decece8120be61423185c5a2 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 27 Aug 2019 15:20:01 +0200 Subject: [PATCH 22/57] Feature/azure-subnets (#440) - Added minimal cluster config for Azure - Updated minimal cluster config for AWS - Added security group with subnet per component. - Added VM defaults. - Added VM Terraform Jinja Template - Added VM to AzureInfraBuilder - Fixed missing module __init__ files --- .../src/epicli/cli/engine/ansible/__init__.py | 0 .../providers/aws/InfrastructureBuilder.py | 13 +-- .../providers/azure/InfrastructureBuilder.py | 83 +++++++++++++- core/src/epicli/cli/engine/schema/__init__.py | 0 .../epicli/cli/engine/terraform/__init__.py | 0 .../configuration/minimal-cluster-config.yml | 2 +- .../configuration/minimal-cluster-config.yml | 30 ++++++ .../infrastructure/security-group.yml | 7 ++ .../azure/defaults/infrastructure/subnet.yml | 9 ++ .../infrastructure/virtual-machine.yml | 102 ++++++++++++------ .../infrastructure/security-group.j2 | 17 +++ .../azure/terraform/infrastructure/subnet.j2 | 19 ++++ .../infrastructure/virtual-machine.j2 | 68 +++++++++++- .../infrastructure/security-group.yml | 1 + .../validation/infrastructure/subnet.yml | 1 + .../azure/test_AzureConfigBuilder.py | 25 +++++ 16 files changed, 330 insertions(+), 47 deletions(-) create mode 100644 core/src/epicli/cli/engine/ansible/__init__.py create mode 100644 core/src/epicli/cli/engine/schema/__init__.py create mode 100644 core/src/epicli/cli/engine/terraform/__init__.py create mode 100644 core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/security-group.yml create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/subnet.yml create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 create mode 100644 core/src/epicli/data/azure/validation/infrastructure/security-group.yml create mode 100644 core/src/epicli/data/azure/validation/infrastructure/subnet.yml diff --git a/core/src/epicli/cli/engine/ansible/__init__.py b/core/src/epicli/cli/engine/ansible/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py index 844c239c8a..bb3c44fdb5 100644 --- a/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/aws/InfrastructureBuilder.py @@ -200,15 +200,12 @@ def get_public_key(self): else: public_key_config.specification.key_name = self.cluster_model.specification.admin_user.name + '-' \ + str(uuid.uuid4()) - if os.path.isfile(self.cluster_model.specification.admin_user.key_path + '.pub'): - with open(self.cluster_model.specification.admin_user.key_path + '.pub', 'r') as stream: - public_key_config.specification.public_key = stream.read().rstrip() + pub_key_path = self.cluster_model.specification.admin_user.key_path + '.pub' + if os.path.isfile(pub_key_path): + with open(pub_key_path, 'r') as stream: + public_key_config.specification.public_key = stream.read().rstrip() else: - raise Exception( - 'SSH key path "' + self.cluster_model.specification.admin_user.key_path + '.pub' + - '" is not valid. Ansible run will fail.') - - + raise Exception(f'SSH key path "{pub_key_path}" is not valid. Ansible run will fail.') return public_key_config def add_security_rules_inbound_efs(self, infrastructure, security_group): diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 267fbd4dbe..1c7a86da03 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -1,8 +1,12 @@ +import os +import uuid + from cli.helpers.Step import Step from cli.helpers.naming_helpers import resource_name from cli.helpers.doc_list_helpers import select_single, select_all from cli.helpers.doc_list_helpers import select_first from cli.helpers.data_loader import load_yaml_obj, types +from cli.helpers.config_merger import merge_with_defaults class InfrastructureBuilder(Step): def __init__(self, docs): @@ -12,6 +16,8 @@ def __init__(self, docs): self.cluster_prefix = self.cluster_model.specification.prefix.lower() self.resource_group_name = resource_name(self.cluster_prefix, self.cluster_name, 'rg') self.region = self.cluster_model.specification.cloud.region + # For linux we dont need a PW since we only support SSH so just add something random for now. + self.lnx_vm_pw = str(uuid.uuid4()) self.docs = docs def run(self): @@ -23,6 +29,38 @@ def run(self): vnet = self.get_virtual_network() infrastructure.append(vnet) + for component_key, component_value in self.cluster_model.specification.components.items(): + vm_count = component_value['count'] + if vm_count < 1: + continue + + #TODO: For now we just take the first subnet definition. Still need to research subnets spread over seperate AAZ`s + if ((component_value.subnets == None) or len(component_value.subnets) == 0): + raise Exception(f'No subnet definition for component: { component_key }') + + if (len(component_value.subnets) > 1): + self.logger.warning(f'On Azure only one subnet per component is supported for now. Taking first and ignoring others.') + + subnet_definition = component_value.subnets[0] + availability_zone = subnet_definition['availability_zone'] + self.logger.info(f'Ignoring availability-zone: { availability_zone } for subnet for component {component_key}') + + subnet = select_first(infrastructure, lambda item: item.kind == 'infrastructure/subnet' and + item.specification.address_prefix == subnet_definition['address_pool']) + + if subnet is None: + security_group = self.get_security_group(component_key, 0) + infrastructure.append(security_group) + + subnet = self.get_subnet(subnet_definition, component_key, security_group.specification.name, 0) + infrastructure.append(subnet) + + #TODO: For now we create the VM infrastructure compatible with the Epiphany 2.x + # code line but later we might want to look at scale sets to achieve the same result: + # https://www.terraform.io/docs/providers/azurerm/r/virtual_machine_scale_set.html + for index in range(vm_count): + infrastructure.append(self.get_vm(component_key, component_value, index)) + return infrastructure def get_resource_group(self): @@ -35,12 +73,53 @@ def get_virtual_network(self): vnet = self.get_config_or_default(self.docs, 'infrastructure/vnet') vnet.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vnet') vnet.specification.address_space = self.cluster_model.specification.cloud.vnet_address_pool - return vnet + return vnet + + def get_security_group(self, component_key, index): + security_group = self.get_config_or_default(self.docs, 'infrastructure/security-group') + security_group.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'security-group' + '-' + str(index), component_key) + return security_group + + def get_subnet(self, subnet_definition, component_key, security_group_name, index): + subnet = self.get_config_or_default(self.docs, 'infrastructure/subnet') + subnet.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'subnet' + '-' + str(index), component_key) + subnet.specification.address_prefix = subnet_definition['address_pool'] + subnet.specification.security_group_name = security_group_name + subnet.specification.cluster_name = self.cluster_name + return subnet + + def get_vm(self, component_key, component_value, index): + vm = self.get_virtual_machine(component_value, self.cluster_model, self.docs) + vm.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vm' + '-' + str(index), component_key) + vm.specification.admin_username = self.cluster_model.specification.admin_user.name + if vm.specification.os_type == 'linux': + # For linux we dont need a PW since we only support SSH so just add something random. + vm.specification.admin_password = self.lnx_vm_pw + if vm.specification.os_type == 'windows': + #TODO: We need PW or can we support SSH or something different on Windows? + vm.specification.admin_password = 'TODO' + pub_key_path = self.cluster_model.specification.admin_user.key_path + '.pub' + if os.path.isfile(pub_key_path): + vm.specification.public_key = pub_key_path + else: + raise Exception(f'SSH key path "{pub_key_path}" is not valid. Ansible run will fail.') + return vm @staticmethod def get_config_or_default(docs, kind): config = select_first(docs, lambda x: x.kind == kind) if config is None: return load_yaml_obj(types.DEFAULT, 'azure', kind) - return config + return config + + @staticmethod + def get_virtual_machine(component_value, cluster_model, docs): + machine_selector = component_value.machine + model_with_defaults = select_first(docs, lambda x: x.kind == 'infrastructure/virtual-machine' and + x.name == machine_selector) + if model_with_defaults is None: + model_with_defaults = merge_with_defaults(cluster_model.provider, 'infrastructure/virtual-machine', + machine_selector) + + return model_with_defaults diff --git a/core/src/epicli/cli/engine/schema/__init__.py b/core/src/epicli/cli/engine/schema/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/epicli/cli/engine/terraform/__init__.py b/core/src/epicli/cli/engine/terraform/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml index 90cabf1b4d..53add74846 100644 --- a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml @@ -5,7 +5,7 @@ provider: aws name: "default" specification: name: YOUR_CLUSTER_NAME - prefix: '' + prefix: YOUR_CLUSTER_RESOURCES_PREFIX admin_user: name: operations # YOUR-ADMIN-USERNAME key_path: /user/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH diff --git a/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml new file mode 100644 index 0000000000..265392edf2 --- /dev/null +++ b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml @@ -0,0 +1,30 @@ +kind: epiphany-cluster +version: 0.3.0 +title: "Epiphany cluster Config" +provider: azure +name: "default" +specification: + name: YOUR_CLUSTER_NAME + prefix: YOUR_CLUSTER_RESOURCES_PREFIX + admin_user: + name: operations # YOUR-ADMIN-USERNAME + key_path: /user/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH + cloud: + use_public_ips: False # When not using public IPs you have to provide connectivity via private IPs (VPN) + components: + kubernetes_master: + count: 1 + kubernetes_node: + count: 3 + logging: + count: 1 + monitoring: + count: 1 + kafka: + count: 2 + postgresql: + count: 1 + load_balancer: + count: 1 + rabbitmq: + count: 1 diff --git a/core/src/epicli/data/azure/defaults/infrastructure/security-group.yml b/core/src/epicli/data/azure/defaults/infrastructure/security-group.yml new file mode 100644 index 0000000000..8d42ccc94b --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/security-group.yml @@ -0,0 +1,7 @@ +kind: infrastructure/security-group +version: 0.3.0 +title: "Security Group Config" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml new file mode 100644 index 0000000000..1a6e324ee9 --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml @@ -0,0 +1,9 @@ +kind: infrastructure/subnet +version: 0.3.0 +title: "Subnet Config" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + address_prefix: SET_BY_AUTOMATION + security_group_name: SET_BY_AUTOMATION diff --git a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml index 8e896f4009..82744194d8 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml @@ -4,44 +4,78 @@ title: "Virtual Machine Infra" provider: azure name: default specification: - count: SET_BY_AUTOMATION - subnet: SET_BY_AUTOMATION - tags: - - version: 0.3.0 - size: Standard_DS1_v2 + name: SET_BY_AUTOMATION + admin_username: SET_BY_AUTOMATION + admin_password: SET_BY_AUTOMATION + public_key: SET_BY_AUTOMATION os_type: linux - disks: - osDisk: - name: os-disk - # size: 40 # not supported by Azure - additional_disks: - - name: secondary - size: 60 - mount_path: "" - network: - subnet: my-subnet-name - network_interfaces: - - name: "nic" - is_primary: true - # This only works with certain size VMs - # Accelerated Networking is supported on most general purpose and compute-optimized instance sizes with 2 or more vCPUs. - # These supported series are: D/DSv2 and F/Fs. On instances that support hyperthreading, Accelerated Networking is supported - # on VM instances with 4 or more vCPUs. Supported series are: D/DSv3, E/ESv3, Fsv2, and Ms/Mms. - # https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli - enable_accelerated_networking: false - ip_configuration: - - name: private-ip - allocation: dynamic - + size: Standard_DS1_v2 + storage_image_reference: + publisher: Canonical + offer: UbuntuServer + sku: 18.04-LTS + version: "18.04.201810030" # Never put latest on anything! Need to always pin the version number but testing we can get away with it + storage_os_disk: + delete_on_termination: false + managed: false + caching: ReadWrite + create_option: FromImage + disk_size_gb: 30 + managed_disk_type: Premium_LRS + security: [] +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: load-balancer-machine +specification: + size: Standard_DS1_v2 +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: kubernetes-master-machine +specification: + size: Standard_DS2_v2 +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: kubernetes-node-machine +specification: + size: Standard_DS1_v2 +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: kafka-machine +specification: + size: Standard_DS2_v +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: monitoring-machine +specification: + size: Standard_DS1_v2 +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: logging-machine +specification: + size: Standard_DS1_v2 --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: default-external-disk +name: postgresql-machine specification: - disks: - additional_disks: - - name: secondary - size: 120 - mount_path: "" + size: Standard_DS1_v2 diff --git a/core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 b/core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 new file mode 100644 index 0000000000..e312ad752b --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 @@ -0,0 +1,17 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_network_security_group" "{{ specification.name }}" { + name = "{{ specification.name }}" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 b/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 new file mode 100644 index 0000000000..c1f54c52e7 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 @@ -0,0 +1,19 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_subnet" "{{ specification.name }}" { + name = "{{ specification.name }}" + address_prefix = "{{ specification.address_prefix }}" + resource_group_name = "${azurerm_resource_group.rg.name}" + virtual_network_name = "${azurerm_virtual_network.vnet.name}" + network_security_group_id = "${azurerm_network_security_group.{{ specification.security_group_name}}.id}" +} diff --git a/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 b/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 index 88657650aa..b6738708b2 100644 --- a/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 +++ b/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 @@ -1,5 +1,69 @@ ##################################################### -# VMs - {{ name }} +# DO NOT Modify by hand - Managed by Automation ##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_virtual_machine" "{{ specification.name }}" { + name = "{{ specification.name }}" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + vm_size = "{{ specification.size }}" + network_interface_ids = [] #TODO + + storage_image_reference { + publisher = "{{ specification.storage_image_reference.publisher }}" + offer = "{{ specification.storage_image_reference.offer }}" + sku = "{{ specification.storage_image_reference.sku }}" + version = "{{ specification.storage_image_reference.version }}" + } + + os_profile { + computer_name = "{{ specification.name }}" + admin_username = "{{ specification.admin_username }}" + admin_password = "{{ specification.admin_password }}" + } + + {%- if specification.os_type == "linux" %} + os_profile_linux_config { + disable_password_authentication = true + ssh_keys { + path = "/home/{{ specification.admin_username }}/.ssh/authorized_keys" + key_data = "${file("{{ specification.public_key }}")}" + } + } + {%- endif %} + + {%- if specification.os_type == "windows" %} + # windows specific stuff here maybe... hopefully never. + {%- endif %} + + {%- if specification.storage_os_disk.managed != true %} + delete_os_disk_on_termination = "{{ specification.storage_os_disk.delete_on_termination | lower }}" + {%- endif %} + storage_os_disk { + name = "{{ specification.name }}-os-disk" + caching = "{{ specification.storage_os_disk.caching }}" + create_option = "{{ specification.storage_os_disk.create_option }}" + {%- if specification.storage_os_disk.managed != true %} + managed_disk_type = "{{ specification.storage_os_disk.managed_disk_type | lower }}" + {%- else %} + #TODO: Container storage + #{%- if specification.storage_container.enable %} + #vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.storage_container_{{ specification.name }}.name}/{{ specification.name }}-${format("%03d", count.index + 1)}-os-disk.vhd" + #{%- endif %} + {%- endif %} + } -# TODO: Fill template + #TODO: + # availability_set_id + # network_interface_ids + # storage_data_disk + # provisioners +} diff --git a/core/src/epicli/data/azure/validation/infrastructure/security-group.yml b/core/src/epicli/data/azure/validation/infrastructure/security-group.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/security-group.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/data/azure/validation/infrastructure/subnet.yml b/core/src/epicli/data/azure/validation/infrastructure/subnet.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/subnet.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py index a014fd6b87..7db3d4742c 100644 --- a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py @@ -23,6 +23,31 @@ def test_get_virtual_network_should_set_proper_values_to_model(): assert actual.specification.address_space == '10.22.0.0/22' +def test_get_security_group_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_security_group('component', 1) + + assert actual.specification.name == 'prefix-testcluster-component-security-group-1' + + +def test_get_subnet_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + subnet_definition = dict_to_objdict({ + 'address_pool': '10.20.0.0/24', + 'availability_zone': 'eu-west-2a' + }) + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_subnet(subnet_definition, 'component', 'prefix-testcluster-component-security-group-1', 1) + + assert actual.specification.name == 'prefix-testcluster-component-subnet-1' + assert actual.specification.address_prefix == subnet_definition['address_pool'] + assert actual.specification.security_group_name == 'prefix-testcluster-component-security-group-1' + assert actual.specification.cluster_name == 'testcluster' + + def get_cluster_model(address_pool='10.22.0.0/22', cluster_name='EpiphanyTestCluster'): cluster_model = dict_to_objdict({ 'kind': 'epiphany-cluster', From 30152417ea5d5d6b1d3d337f82f40ae717d95649 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 28 Aug 2019 16:36:00 +0200 Subject: [PATCH 23/57] Changing epicli output directory (#441) --- core/src/epicli/tests/docker/test-ci-epicli/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/tests/docker/test-ci-epicli/run.sh b/core/src/epicli/tests/docker/test-ci-epicli/run.sh index b7c81b98b8..ef552ced00 100644 --- a/core/src/epicli/tests/docker/test-ci-epicli/run.sh +++ b/core/src/epicli/tests/docker/test-ci-epicli/run.sh @@ -9,7 +9,7 @@ then echo "Epiphany build for cluster $CLUSTER_NAME completed successfully" echo echo "Serverspec tests for cluster $CLUSTER_NAME started..." - rake inventory="/shared/$CLUSTER_NAME/inventory" user=$ADMIN_USERNAME keypath=$KEY_PATH spec:all + rake inventory="/shared/build/$CLUSTER_NAME/inventory" user=$ADMIN_USERNAME keypath=$KEY_PATH spec:all echo "Serverspec tests for cluster $CLUSTER_NAME finished" echo else From 604a237beb5feaed2975de333cfe6a64327e1f5b Mon Sep 17 00:00:00 2001 From: lukurde <47138492+lukurde@users.noreply.github.com> Date: Thu, 29 Aug 2019 10:04:23 +0200 Subject: [PATCH 24/57] always apt update before apt install (#442) --- core/src/epicli/cli/engine/ansible/AnsibleRunner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py index 3dd88eb788..22b7d03eec 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py @@ -42,7 +42,7 @@ def run(self): # todo: install packages to run ansible on Red Hat hosts self.ansible_command.run_task_with_retries(hosts="all", inventory=inventory_path, module="raw", args="cat /etc/lsb-release | grep -i DISTRIB_ID | grep -i ubuntu && " - "sudo apt-get install -y python-simplejson " + "sudo apt-get update && sudo apt-get install -y python-simplejson " "|| echo 'Cannot find information about Ubuntu distribution'", retries=5) self.ansible_vars_generator.run() From f24ff2e1bf9c66c2e9ceb4608c25743668391769 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Thu, 29 Aug 2019 15:20:56 +0200 Subject: [PATCH 25/57] Workaround for RspecJUnitFormatter encoding issue (#445) --- .../epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb index cabc64bf82..f1a4d48628 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/haproxy/haproxy_spec.rb @@ -8,7 +8,7 @@ # https://bugzilla.redhat.com/show_bug.cgi?id=1073481 describe 'Checking HAProxy service status' do - describe command("systemctl status haproxy") do + describe command("systemctl status haproxy > /dev/null") do its(:exit_status) { should eq 0 } end end From 1a6ef4edc4e964590538f63d7d500c0100bb4f2a Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Mon, 2 Sep 2019 09:17:25 +0200 Subject: [PATCH 26/57] Added docs on how to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 (#447) * Removing the test environment destruction function * Added docs on how to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 * Added docs on how to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 --- docs/home/HOWTO.md | 134 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index 41720f3a3c..d0ceada982 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -37,6 +37,7 @@ - [How to setup Azure VM as docker machine for development](#how-to-setup-azure-vm-as-docker-machine-for-development) - [How to upgrade Kubernetes cluster](#how-to-upgrade-kubernetes-cluster) - [How to upgrade Kubernetes cluster from 1.13.0 to 1.13.1](#how-to-upgrade-kubernetes-cluster-from-1130-to-1131) + - [How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch](#how-to-upgrade-kubernetes-cluster-from-1131-to-11310--latest-patch) - [How to authenticate to Azure AD app](#how-to-authenticate-to-azure-ad-app) - [How to expose service through HA Proxy load balancer](#how-to-expose-service-through-ha-proxy-load-balancer) - Security @@ -1126,6 +1127,139 @@ Worker nodes will be upgraded one by one - it will prevent application downtime. ``` +## How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch + +### RHEL + +#### Upgrade Master + +Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) + +##### > RUN ON MASTER + +1. Check kubeadm version +```bash +kubeadm version +# should show v1.13.1 +``` +2. Find the latest stable 1.13 version +```bash +yum list --showduplicates kubeadm --disableexcludes=kubernetes +# 1.13.10-0 +``` +3. Drain master in preparation for maintenance +```bash +kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] +# $MASTER should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +4. Wait for all pods to be running and ready + +5. Install packages +```bash +sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes +``` +6. Validate whether current cluster is upgradeable +```bash +sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +7. Upgrade Kubernetes cluster to the specified version +```bash +sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +8. Wait for all pods to be running and ready + +9. Reload daemon +```bash +sudo systemctl daemon-reload +``` +10. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +11. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +12. Wait for cluster to be ready, e.g. check: +```bash +kubectl cluster-info +``` +13. Uncordon master - mark as schedulable +```bash +kubectl uncordon $MASTER +``` +14. List all nodes +```bash +kubectl get nodes +# should return $MASTER in status "Ready" and version 1.13.10 +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Important: Worker nodes should be upgraded one by one - this will prevent application downtime. + +##### > RUN ON MASTER + +1. Drain node in preparation for maintenance +```bash +kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] +# $NODE should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +2. Wait for all pods to be running and ready + +##### > RUN ON NODE + +3. Install packages +```bash +sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes +``` +4. Upgrade node config +```bash +sudo kubeadm upgrade node config --kubelet-version v1.13.10 +``` +5. Reload daemon +```bash +sudo systemctl daemon-reload +``` +6. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +7. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +##### > RUN ON MASTER + +8. Uncordon node - mark as schedulable +```bash +kubectl uncordon $NODE +``` +9. List all nodes +```bash +kubectl get nodes +# should return $NODE in status "Ready" and version 1.13.10 +``` +10. Go back to the point 1 with the next node + ## How to upgrade Kafka cluster ### Kafka upgrade From c905bce5cf51f70eb9cb05a9a7e7d583de982977 Mon Sep 17 00:00:00 2001 From: erzetpe Date: Mon, 2 Sep 2019 12:04:40 +0200 Subject: [PATCH 27/57] Fix rabbit bad exporter and ports (#446) --- core/src/epicli/cli/epicli.py | 40 ++++++------ .../infrastructure/virtual-machine.yml | 63 +++++++++++++++++++ .../configuration/feature-mapping.yml | 1 - .../data/common/defaults/epiphany-cluster.yml | 3 +- 4 files changed, 86 insertions(+), 21 deletions(-) diff --git a/core/src/epicli/cli/epicli.py b/core/src/epicli/cli/epicli.py index c8ad612acf..2b6158c457 100644 --- a/core/src/epicli/cli/epicli.py +++ b/core/src/epicli/cli/epicli.py @@ -16,7 +16,6 @@ def main(): - config = Config() parser = argparse.ArgumentParser( description=__doc__, @@ -38,14 +37,15 @@ def main(): help='Roleover count where each CLI run will generate a new log.') parser.add_argument('--log-type', choices=['plain', 'json'], default='plain', dest='log_type', action='store', help='Type of logs.') - parser.add_argument('--validate-certs', choices=['true', 'false'], default='true', action='store', dest='validate_certs', + parser.add_argument('--validate-certs', choices=['true', 'false'], default='true', action='store', + dest='validate_certs', help='''[Experimental]: Disables certificate checks for certain Ansible operations which might have issues behind proxies (https://github.com/ansible/ansible/issues/32750). Should NOT be used in production for security reasons.''') parser.add_argument('--debug', dest='debug', action="store_true", - help='Set this to output extensive debug information. Carries over to Ansible and Terraform.') + help='Set this to output extensive debug information. Carries over to Ansible and Terraform.') parser.add_argument('--auto-approve', dest='auto_approve', action="store_true", - help='Auto approve any user input queries asked by Epicli') + help='Auto approve any user input queries asked by Epicli') # some arguments we don't want available when running from the docker image. if not config.docker_cli: parser.add_argument('-o', '--output', dest='output_dir', type=str, @@ -88,9 +88,11 @@ def main(): logger.error(e, exc_info=config.debug) return 1 + def init_parser(subparsers): sub_parser = subparsers.add_parser('init', description='Creates configuration file in working directory.') - sub_parser.add_argument('-p', '--provider', dest='provider', choices=['aws', 'azure', 'any'], default='any', type=str, + sub_parser.add_argument('-p', '--provider', dest='provider', choices=['aws', 'azure', 'any'], default='any', + type=str, required=True, help='One of the supported providers: azure|aws|any') sub_parser.add_argument('-n', '--name', dest='name', type=str, required=True, help='Name of the cluster.') @@ -103,7 +105,7 @@ def run_init(args): with InitEngine(args) as engine: return engine.init() - sub_parser.set_defaults(func=run_init) + sub_parser.set_defaults(func=run_init) def apply_parser(subparsers): @@ -116,7 +118,7 @@ def apply_parser(subparsers): def run_apply(args): adjust_paths_from_file(args) with BuildEngine(args) as engine: - return engine.apply() + return engine.apply() sub_parser.set_defaults(func=run_apply) @@ -147,13 +149,14 @@ def run_delete(args): return 0 adjust_paths_from_build(args) with DeleteEngine(args) as engine: - return engine.delete() + return engine.delete() - sub_parser.set_defaults(func=run_delete) + sub_parser.set_defaults(func=run_delete) def upgrade_parser(subparsers): - sub_parser = subparsers.add_parser('upgrade', description='[Experimental]: Upgrades existing Epiphany Platform to latest version.') + sub_parser = subparsers.add_parser('upgrade', + description='[Experimental]: Upgrades existing Epiphany Platform to latest version.') sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, help='Absolute path to directory with build artifacts.') @@ -167,7 +170,8 @@ def run_upgrade(args): def backup_parser(subparsers): - sub_parser = subparsers.add_parser('backup', description='[Experimental]: Backups existing Epiphany Platform components.') + sub_parser = subparsers.add_parser('backup', + description='[Experimental]: Backups existing Epiphany Platform components.') sub_parser.add_argument('-b', '--build', dest='build_directory', type=str, required=True, help='Absolute path to directory with build artifacts.') @@ -196,15 +200,15 @@ def run_recovery(args): def experimental_query(): if not query_yes_no('This is an experimental feature and could change at any time. Do you want to continue?'): - sys.exit(0) + sys.exit(0) def adjust_paths_from_file(args): if not os.path.isabs(args.file): args.file = os.path.join(os.getcwd(), args.file) if not os.path.isfile(args.file): - Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. - raise Exception(f'File "{args.file}" does not excist') + Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. + raise Exception(f'File "{args.file}" does not excist') if Config().output_dir is None: Config().output_dir = os.path.join(os.path.dirname(args.file), 'build') dump_config(Config()) @@ -214,9 +218,9 @@ def adjust_paths_from_build(args): if not os.path.isabs(args.build_directory): args.build_directory = os.path.join(os.getcwd(), args.build_directory) if not os.path.exists(args.build_directory): - Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. - raise Exception(f'Build directory "{args.build_directory}" does not excist') - if args.build_directory[-1:] == '/': + Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. + raise Exception(f'Build directory "{args.build_directory}" does not excist') + if args.build_directory[-1:] == '/': args.build_directory = args.build_directory.rstrip('/') if Config().output_dir is None: Config().output_dir = os.path.split(args.build_directory)[0] @@ -227,7 +231,7 @@ def dump_config(config): logger = Log('config') for attr in config.__dict__: if attr.startswith('_'): - logger.info ('%s = %r' % (attr[1:], getattr(config, attr))) + logger.info('%s = %r' % (attr[1:], getattr(config, attr))) if __name__ == '__main__': diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 5c7aa2787c..f80c701298 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -41,6 +41,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 @@ -65,6 +75,16 @@ specification: os_type: linux security: rules: + - name: ssh + description: Allow SSH + priority: 101 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" - name: node_exporter description: Allow node_exporter traffic priority: 302 @@ -80,6 +100,49 @@ kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: aws +name: rabbitmq-machine +specification: + tags: + - version: 0.3.0 + size: t3.micro + os_type: linux + security: + rules: + - name: ssh + description: Allow SSH + priority: 101 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: rabbitmq + description: Allow rabbitmq traffic + priority: 303 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "5672" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: aws name: load-balancer-machine specification: tags: diff --git a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml index 531f7e3a33..9c79a0152e 100644 --- a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml +++ b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml @@ -51,7 +51,6 @@ specification: rabbitmq: - rabbitmq - node-exporter - - kafka-exporter - filebeat logging: - elasticsearch diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 19934a2d31..410ce94eca 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -65,7 +65,6 @@ specification: subnets: - availability_zone: eu-west-2a address_pool: 10.1.6.0/24 - load_balancer: count: 1 machine: load-balancer-machine @@ -75,7 +74,7 @@ specification: address_pool: 10.1.7.0/24 rabbitmq: count: 0 - machine: default + machine: rabbitmq-machine configuration: default subnets: - availability_zone: eu-west-2a From e46a10be0e7c1e0281e7e1a741977e9503b5c657 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Tue, 3 Sep 2019 12:42:12 +0200 Subject: [PATCH 28/57] Added docs on how to upgrade Kubernetes cluster on Ubuntu (#457) --- docs/home/HOWTO.md | 137 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index d0ceada982..e9f89d6f0b 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -1129,6 +1129,143 @@ Worker nodes will be upgraded one by one - it will prevent application downtime. ## How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch +### Ubuntu Server + +#### Upgrade Master + +Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) + +##### > RUN ON MASTER + +1. Check kubeadm version +```bash +kubeadm version +# should show v1.13.1 +``` +2. Find the latest stable 1.13 version +```bash +sudo apt update +apt-cache policy kubeadm +# 1.13.10-0 +``` +3. Drain master in preparation for maintenance +```bash +kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] +# $MASTER should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +4. Wait for all pods to be running and ready + +5. Install packages +```bash +sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ +sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ +sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm +``` +6. Validate whether current cluster is upgradeable +```bash +sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +7. Upgrade Kubernetes cluster to the specified version +```bash +sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +8. Wait for all pods to be running and ready + +9. Reload daemon +```bash +sudo systemctl daemon-reload +``` +10. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +11. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +12. Wait for cluster to be ready, e.g. check: +```bash +kubectl cluster-info +``` +13. Uncordon master - mark as schedulable +```bash +kubectl uncordon $MASTER +``` +14. List all nodes +```bash +kubectl get nodes +# should return $MASTER in status "Ready" and version 1.13.10 +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Important: Worker nodes should be upgraded one by one - this will prevent application downtime. + +##### > RUN ON MASTER + +1. Drain node in preparation for maintenance +```bash +kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] +# $NODE should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +2. Wait for all pods to be running and ready + +##### > RUN ON NODE + +3. Install packages +```bash +sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ +sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ +sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm +``` +4. Upgrade node config +```bash +sudo kubeadm upgrade node config --kubelet-version v1.13.10 +``` +5. Reload daemon +```bash +sudo systemctl daemon-reload +``` +6. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +7. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +##### > RUN ON MASTER + +8. Uncordon node - mark as schedulable +```bash +kubectl uncordon $NODE +``` +9. List all nodes +```bash +kubectl get nodes +# should return $NODE in status "Ready" and version 1.13.10 +``` +10. Go back to the point 1 with the next node + + ### RHEL #### Upgrade Master From 28b5364c35805890a2ce24d979a8258514488515 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Tue, 3 Sep 2019 12:42:20 +0200 Subject: [PATCH 29/57] Allow outgoing connections on rabbitmq vms (#456) --- .../aws/defaults/infrastructure/virtual-machine.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index f80c701298..8593015543 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -138,6 +138,16 @@ specification: destination_port_range: "5672" source_address_prefix: "10.1.0.0/20" destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Egress + access: Allow + protocol: "all" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 From be7c12d1be0a7a90393934a3ec7c2823cb59650f Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 4 Sep 2019 11:46:21 +0200 Subject: [PATCH 30/57] Wait for the cluster to be available before running deployments/applications playbook (#467) --- core/core/src/ansible/roles/deployments/tasks/main.yml | 7 +++++++ .../ansible/playbooks/roles/applications/tasks/main.yml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/core/core/src/ansible/roles/deployments/tasks/main.yml b/core/core/src/ansible/roles/deployments/tasks/main.yml index 5e473584d1..541e6d8dab 100644 --- a/core/core/src/ansible/roles/deployments/tasks/main.yml +++ b/core/core/src/ansible/roles/deployments/tasks/main.yml @@ -1,4 +1,11 @@ --- +- name: Wait until the cluster is available + shell: kubectl --kubeconfig=/home/{{ admin_user.name }}/.kube/config cluster-info + retries: 10 + delay: 5 + register: output + until: output is succeeded + - name: Include deployments include_tasks: "applications/{{ item.name }}/main.yml" vars: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/applications/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/applications/tasks/main.yml index 13b901603e..b1294233c8 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/applications/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/applications/tasks/main.yml @@ -1,4 +1,11 @@ --- +- name: Wait until the cluster is available + shell: kubectl --kubeconfig=/home/{{ admin_user.name }}/.kube/config cluster-info + retries: 10 + delay: 5 + register: output + until: output is succeeded + - name: Include applications include_tasks: "applications/{{ item.name }}/main.yml" vars: From c4b119969aa20419ad13a3097e6963eed3a892bc Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 4 Sep 2019 16:41:31 +0200 Subject: [PATCH 31/57] Changed ansible default 10s ping timeout to 60s; added junit xml reports for unit tests (#468) --- core/core/src/templates/common/ansible.sh.j2 | 2 +- core/src/epicli/run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/core/src/templates/common/ansible.sh.j2 b/core/core/src/templates/common/ansible.sh.j2 index 03fc793098..9b86d81a1c 100644 --- a/core/core/src/templates/common/ansible.sh.j2 +++ b/core/core/src/templates/common/ansible.sh.j2 @@ -186,7 +186,7 @@ $REPO_ROOT/bin/template_engine -d $EPIPHANY_DATA_DIR/data/manifest.yaml -i $REPO echo_yellow '====> Verifying Ansible access to nodes...' -ansible all -i $EPIPHANY_DATA_DIR/inventory/$ANSIBLE_ENV -m ping +ansible all -i $EPIPHANY_DATA_DIR/inventory/$ANSIBLE_ENV -m ping --timeout=60 if [[ $? -ne 0 ]]; then echo_red "ERROR: Unable to reach all of the hosts in the cluster. Verify 'manifest.yaml' is correct and run this again." diff --git a/core/src/epicli/run-tests.sh b/core/src/epicli/run-tests.sh index 210dd95e62..8bd07f2b7b 100755 --- a/core/src/epicli/run-tests.sh +++ b/core/src/epicli/run-tests.sh @@ -1,4 +1,4 @@ # Run the python test for Epicli mkdir -p tests_result -python -m pytest ./tests/ | tee tests_result/result.txt +python -m pytest ./tests/ --junit-xml=tests_result/result.xml | tee tests_result/result.txt echo "Done running tests. See tests_result/result.txt" \ No newline at end of file From 631891fa6d56a4ebb71c5aeaccba7e4b05acfd60 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 10 Sep 2019 10:57:27 +0200 Subject: [PATCH 32/57] Feature/skopeo (#475) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * - Added Skopeo minor update to devcontainer. --- .../epicli/.devcontainer/devcontainer.json | 8 +- core/src/epicli/Pipfile | 1 + core/src/epicli/Pipfile.lock | 92 ++++++++++--------- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/core/src/epicli/.devcontainer/devcontainer.json b/core/src/epicli/.devcontainer/devcontainer.json index 175e8fcc20..f1468e951a 100644 --- a/core/src/epicli/.devcontainer/devcontainer.json +++ b/core/src/epicli/.devcontainer/devcontainer.json @@ -2,7 +2,13 @@ "name": "epicli", "dockerFile": "Dockerfile", "extensions": [ - "ms-python.python" + "ms-python.python", + "littlefoxteam.vscode-python-test-adapter", + "vscoss.vscode-ansible", + "wholroyd.jinja", + "redhat.vscode-yaml", + "mauve.terraform", + "davidanson.vscode-markdownlint" ], "settings": { "python.pythonPath": "/usr/local/bin/python", diff --git a/core/src/epicli/Pipfile b/core/src/epicli/Pipfile index ed5f207f30..9cb19e19d7 100644 --- a/core/src/epicli/Pipfile +++ b/core/src/epicli/Pipfile @@ -18,6 +18,7 @@ python-json-logger = "*" ansible = "*" terraform-bin = "*" azure-cli = "==2.0.67" +skopeo-bin = "*" [requires] python_version = "3.7" diff --git a/core/src/epicli/Pipfile.lock b/core/src/epicli/Pipfile.lock index 145e40a02b..538fe308e8 100644 --- a/core/src/epicli/Pipfile.lock +++ b/core/src/epicli/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "72adf6714817ddb52447f1fdaeedbd9562305bd3ace6d71d4af90bdc0c43aff4" + "sha256": "1d4b6c4c5d819486beb8d53fc0b09aaac9e5d92d46f4a5fcb39370ef32ac6859" }, "pipfile-spec": 6, "requires": { @@ -25,10 +25,10 @@ }, "ansible": { "hashes": [ - "sha256:05f9ed3ca3e06dffaa87a73a8e6f7f322825bc3f609f8b71c4fe22dbbdf72abc" + "sha256:a0153e2de3619b7e307df179cd91a3c3804cf1fe048273fe4ea5238b76679ff1" ], "index": "pypi", - "version": "==2.8.3" + "version": "==2.8.4" }, "antlr4-python3-runtime": { "hashes": [ @@ -1010,18 +1010,18 @@ }, "boto3": { "hashes": [ - "sha256:666f37c5852f71925494fc2103b189deafe6702c1d9ae60bead5b1b6466de857", - "sha256:7b77b507221ec15550b02d492804166bcc61ef3a81312968065515a76aa1791b" + "sha256:0c4b88af2bf774992cba6361f0af30ca7c7e9fa0dc0f849f241e73edfdeab2b9", + "sha256:97114b6d43c691c7314f461b74da20aaffcc6dc6afaa47ad22b0bc383b112d8a" ], "index": "pypi", - "version": "==1.9.202" + "version": "==1.9.225" }, "botocore": { "hashes": [ - "sha256:71ca578701e746fe947c098e5dee06128d0f6ba98217ba7e29aff0dab8caf82f", - "sha256:e55003c46e71396a551d4b70f39286f8fc4094ac6cf90f5db8d7a68bb4af1f9d" + "sha256:e6d17290add0a5e8510af92b26ede437bd618f211bc40ad3e4cdf1e7e478b44c", + "sha256:fe4c216f1d35d0b368d1916d9e8e7f1933deb80d52d8f84a5d2797a810deef5c" ], - "version": "==1.12.202" + "version": "==1.12.225" }, "certifi": { "hashes": [ @@ -1100,18 +1100,18 @@ }, "docutils": { "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" ], - "version": "==0.14" + "version": "==0.15.2" }, "fabric": { "hashes": [ - "sha256:93684ceaac92e0b78faae551297e29c48370cede12ff0f853cdebf67d4b87068", - "sha256:98538f2f3f63cf52497a8d0b24d18424ae83fe67ac7611225c72afb9e67f2cf6" + "sha256:160331934ea60036604928e792fa8e9f813266b098ef5562aa82b88527740389", + "sha256:24842d7d51556adcabd885ac3cf5e1df73fc622a1708bf3667bf5927576cdfa6" ], - "version": "==2.4.0" + "version": "==2.5.0" }, "humanfriendly": { "hashes": [ @@ -1129,11 +1129,11 @@ }, "invoke": { "hashes": [ - "sha256:4f4de934b15c2276caa4fbc5a3b8a61c0eb0b234f2be1780d2b793321995c2d6", - "sha256:dc492f8f17a0746e92081aec3f86ae0b4750bf41607ea2ad87e5a7b5705121b7", - "sha256:eb6f9262d4d25b40330fb21d1e99bf0f85011ccc3526980f8a3eaedd4b43892e" + "sha256:c52274d2e8a6d64ef0d61093e1983268ea1fc0cd13facb9448c4ef0c9a7ac7da", + "sha256:f4ec8a134c0122ea042c8912529f87652445d9f4de590b353d23f95bfa1f0efd", + "sha256:fc803a5c9052f15e63310aa81a43498d7c55542beb18564db88a9d75a176fa44" ], - "version": "==1.2.0" + "version": "==1.3.0" }, "isodate": { "hashes": [ @@ -1214,10 +1214,10 @@ }, "msrest": { "hashes": [ - "sha256:27589fb400da7e1a98778688f70a0099e4fc6fea59d0f4835b4fbdad3bb8a6d9", - "sha256:cda706a2ccfb032cf41fa8cc6575cbca29634fed2d226fc789e4a8daf44ab7c1" + "sha256:56b8b5b4556fb2a92cac640df267d560889bdc9e2921187772d4691d97bc4e8d", + "sha256:f5153bfe60ee757725816aedaa0772cbfe0bddb52cd2d6db4cb8b4c3c6c6f928" ], - "version": "==0.6.9" + "version": "==0.6.10" }, "msrestazure": { "hashes": [ @@ -1408,6 +1408,13 @@ ], "version": "==1.12.0" }, + "skopeo-bin": { + "hashes": [ + "sha256:3686491a2e6251a608e767b6a073736d34c0fce212a23947bdac65d8fd7828d8" + ], + "index": "pypi", + "version": "==1.0.2" + }, "sshtunnel": { "hashes": [ "sha256:c813fdcda8e81c3936ffeac47cb69cfb2d1f5e77ad0de656c6dab56aeebd9249" @@ -1518,11 +1525,11 @@ }, "docutils": { "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" ], - "version": "==0.14" + "version": "==0.15.2" }, "idna": { "hashes": [ @@ -1533,10 +1540,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", - "sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3" + "sha256:9ff1b1c5a354142de080b8a4e9803e5d0d59283c93aed808617c787d16768375", + "sha256:b7143592e374e50584564794fcb8aaf00a23025f9db866627f89a21491847a8d" ], - "version": "==0.19" + "markers": "python_version < '3.8'", + "version": "==0.20" }, "more-itertools": { "hashes": [ @@ -1589,11 +1597,11 @@ }, "pytest": { "hashes": [ - "sha256:6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", - "sha256:a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77" + "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", + "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" ], "index": "pypi", - "version": "==5.0.1" + "version": "==5.1.2" }, "readme-renderer": { "hashes": [ @@ -1625,18 +1633,18 @@ }, "tqdm": { "hashes": [ - "sha256:14a285392c32b6f8222ecfbcd217838f88e11630affe9006cd0e94c7eff3cb61", - "sha256:25d4c0ea02a305a688e7e9c2cdc8f862f989ef2a4701ab28ee963295f5b109ab" + "sha256:1be3e4e3198f2d0e47b928e9d9a8ec1b63525db29095cec1467f4c5a4ea8ebf9", + "sha256:7e39a30e3d34a7a6539378e39d7490326253b7ee354878a92255656dc4284457" ], - "version": "==4.32.2" + "version": "==4.35.0" }, "twine": { "hashes": [ - "sha256:0fb0bfa3df4f62076cab5def36b1a71a2e4acb4d1fa5c97475b048117b1a6446", - "sha256:d6c29c933ecfc74e9b1d9fa13aa1f87c5d5770e119f5a4ce032092f0ff5b14dc" + "sha256:b2cec0dc1ac55bd74280d257f43763cf0cf928bdcd0de0fd70be70aa1195e3b0", + "sha256:e37d5a73d77b095b85314dde807bfb85b580b5b9d137f5b21332f4636990d97a" ], "index": "pypi", - "version": "==1.13.0" + "version": "==1.14.0" }, "urllib3": { "extras": [ @@ -1672,10 +1680,10 @@ }, "zipp": { "hashes": [ - "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", - "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec" + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" ], - "version": "==0.5.2" + "version": "==0.6.0" } } } From de8fae28727e9544d4ca45d94631d901604d7d45 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 10 Sep 2019 12:52:25 +0200 Subject: [PATCH 33/57] subnets, network interfaces, security rules, ansible inventory (#469) Fixes for subnets Fixed versions for Terraform providers for both Azure and AWS Added VMs Added network interfaces Added security rules Added ansible inventory generation --- .../cli/engine/providers/azure/APIProxy.py | 16 +- .../providers/azure/InfrastructureBuilder.py | 104 ++- core/src/epicli/cli/helpers/naming_helpers.py | 10 +- .../data/aws/terraform/epiphany-cluster.j2 | 1 + .../infrastructure/network-interface.yml | 13 + ...y-group.yml => network-security-group.yml} | 5 +- .../defaults/infrastructure/public-ip.yml | 10 + ...net-network-security-group-association.yml | 9 + .../azure/defaults/infrastructure/subnet.yml | 2 +- .../infrastructure/virtual-machine.yml | 590 +++++++++++++++++- .../data/azure/terraform/epiphany-cluster.j2 | 1 + .../infrastructure/network-interface.j2 | 30 + .../infrastructure/network-security-group.j2 | 32 + .../terraform/infrastructure/public-ip.j2 | 20 + ...net-network-security-group-association.j2} | 7 +- .../azure/terraform/infrastructure/subnet.j2 | 5 +- .../infrastructure/virtual-machine.j2 | 12 +- ...curity-group.yml => network-interface.yml} | 0 .../infrastructure/network-security-group.yml | 1 + .../validation/infrastructure/public-ip.yml | 1 + ...net-network-security-group-association.yml | 1 + .../azure/test_AzureConfigBuilder.py | 68 +- 22 files changed, 881 insertions(+), 57 deletions(-) create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml rename core/src/epicli/data/azure/defaults/infrastructure/{security-group.yml => network-security-group.yml} (52%) create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/network-interface.j2 create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/network-security-group.j2 create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/public-ip.j2 rename core/src/epicli/data/azure/terraform/infrastructure/{security-group.j2 => subnet-network-security-group-association.j2} (71%) rename core/src/epicli/data/azure/validation/infrastructure/{security-group.yml => network-interface.yml} (100%) create mode 100644 core/src/epicli/data/azure/validation/infrastructure/network-security-group.yml create mode 100644 core/src/epicli/data/azure/validation/infrastructure/public-ip.yml create mode 100644 core/src/epicli/data/azure/validation/infrastructure/subnet-network-security-group-association.yml diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index 5cd82f8f6b..df9454f2f0 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -4,6 +4,8 @@ from subprocess import Popen, PIPE from cli.helpers.Log import LogPipe, Log from cli.helpers.doc_list_helpers import select_first +from cli.helpers.naming_helpers import resource_name +from cli.models.AnsibleHostModel import AnsibleHostModel class APIProxy: def __init__(self, cluster_model, config_docs): @@ -40,9 +42,19 @@ def create_sp(self, app_name, subscription_id): return sp def get_ips_for_feature(self, component_key): + look_for_public_ip = self.cluster_model.specification.cloud.use_public_ips + cluster = f'{self.cluster_model.specification.prefix.lower()}-{self.cluster_model.specification.name.lower()}' + running_instances = self.run(self, f'az vm list-ip-addresses --ids $(az resource list --query "[?type==\'Microsoft.Compute/virtualMachines\' && tags.{component_key} == \'\' && tags.cluster == \'{cluster}\'].id" --output tsv)') result = [] - #TODO: Implement this. - #az vm list-ip-addresses -g {{ resource_group_name }} + for instance in running_instances: + if isinstance(instance, list): + instance = instance[0] + name = instance['virtualMachine']['name'] + if look_for_public_ip: + ip = instance['virtualMachine']['network']['publicIpAddresses'][0]['ipAddress'] + else: + ip = instance['virtualMachine']['network']['privateIpAddresses'][0] + result.append(AnsibleHostModel(name, ip)) return result @staticmethod diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 1c7a86da03..6fe7054080 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -1,5 +1,5 @@ import os -import uuid +from copy import deepcopy from cli.helpers.Step import Step from cli.helpers.naming_helpers import resource_name @@ -7,6 +7,7 @@ from cli.helpers.doc_list_helpers import select_first from cli.helpers.data_loader import load_yaml_obj, types from cli.helpers.config_merger import merge_with_defaults +from cli.helpers.objdict_helpers import objdict_to_dict, dict_to_objdict class InfrastructureBuilder(Step): def __init__(self, docs): @@ -16,8 +17,6 @@ def __init__(self, docs): self.cluster_prefix = self.cluster_model.specification.prefix.lower() self.resource_group_name = resource_name(self.cluster_prefix, self.cluster_name, 'rg') self.region = self.cluster_model.specification.cloud.region - # For linux we dont need a PW since we only support SSH so just add something random for now. - self.lnx_vm_pw = str(uuid.uuid4()) self.docs = docs def run(self): @@ -34,32 +33,59 @@ def run(self): if vm_count < 1: continue - #TODO: For now we just take the first subnet definition. Still need to research subnets spread over seperate AAZ`s - if ((component_value.subnets == None) or len(component_value.subnets) == 0): - raise Exception(f'No subnet definition for component: { component_key }') + # The vm config also contains some other stuff we use for network and security config. + # So get it here and pass it allong. + vm_config = self.get_virtual_machine(component_value, self.cluster_model, self.docs) + # For now only one subnet per component. if (len(component_value.subnets) > 1): - self.logger.warning(f'On Azure only one subnet per component is supported for now. Taking first and ignoring others.') + self.logger.warning(f'On Azure only one subnet per component is supported for now. Taking first and ignoring others.') subnet_definition = component_value.subnets[0] - availability_zone = subnet_definition['availability_zone'] - self.logger.info(f'Ignoring availability-zone: { availability_zone } for subnet for component {component_key}') - subnet = select_first(infrastructure, lambda item: item.kind == 'infrastructure/subnet' and item.specification.address_prefix == subnet_definition['address_pool']) if subnet is None: - security_group = self.get_security_group(component_key, 0) - infrastructure.append(security_group) - - subnet = self.get_subnet(subnet_definition, component_key, security_group.specification.name, 0) - infrastructure.append(subnet) + nsg = self.get_network_security_group(component_key, + vm_config.specification.security.rules, + 0) + infrastructure.append(nsg) + + subnet = self.get_subnet(subnet_definition, component_key, nsg.specification.name, 0) + infrastructure.append(subnet) + + #TODO: This gives issues for now when creating more then 3 subnets. Re-test when + # upgrading from azurerm 1.27 to 2.0 and for now stick to azurerm_subnet.network_security_group_id + #ssga = self.get_subnet_network_security_group_association(component_key, + # subnet.specification.name, + # nsg.specification.name, + # 0) + #infrastructure.append(ssga) #TODO: For now we create the VM infrastructure compatible with the Epiphany 2.x # code line but later we might want to look at scale sets to achieve the same result: # https://www.terraform.io/docs/providers/azurerm/r/virtual_machine_scale_set.html for index in range(vm_count): - infrastructure.append(self.get_vm(component_key, component_value, index)) + public_ip_name = '' + if self.cluster_model.specification.cloud.use_public_ips: + public_ip = self.get_public_ip(component_key, + component_value, + vm_config, + index) + infrastructure.append(public_ip) + public_ip_name = public_ip.specification.name + + network_interface = self.get_network_interface(component_key, + component_value, + vm_config, + subnet.specification.name, + nsg.specification.name, + public_ip_name, + index) + infrastructure.append(network_interface) + + vm = self.get_vm(component_key, component_value, vm_config, network_interface.specification.name, index) + infrastructure.append(vm) return infrastructure @@ -75,10 +101,11 @@ def get_virtual_network(self): vnet.specification.address_space = self.cluster_model.specification.cloud.vnet_address_pool return vnet - def get_security_group(self, component_key, index): - security_group = self.get_config_or_default(self.docs, 'infrastructure/security-group') - security_group.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'security-group' + '-' + str(index), component_key) - return security_group + def get_network_security_group(self, component_key, security_rules, index): + security_group = self.get_config_or_default(self.docs, 'infrastructure/network-security-group') + security_group.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'nsg' + '-' + str(index), component_key) + security_group.specification.rules = security_rules + return security_group def get_subnet(self, subnet_definition, component_key, security_group_name, index): subnet = self.get_config_or_default(self.docs, 'infrastructure/subnet') @@ -88,14 +115,43 @@ def get_subnet(self, subnet_definition, component_key, security_group_name, inde subnet.specification.cluster_name = self.cluster_name return subnet - def get_vm(self, component_key, component_value, index): - vm = self.get_virtual_machine(component_value, self.cluster_model, self.docs) + def get_subnet_network_security_group_association(self, component_key, subnet_name, security_group_name, index): + ssga = self.get_config_or_default(self.docs, 'infrastructure/subnet-network-security-group-association') + ssga.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'ssga' + '-' + str(index), component_key) + ssga.specification.subnet_name = subnet_name + ssga.specification.security_group_name = security_group_name + return ssga + + def get_network_interface(self, component_key, component_value, vm_config, subnet_name, security_group_name, public_ip_name, index): + network_interface = self.get_config_or_default(self.docs, 'infrastructure/network-interface') + network_interface.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'nic' + '-' + str(index), component_key) + network_interface.specification.security_group_name = security_group_name + network_interface.specification.ip_configuration_name = resource_name(self.cluster_prefix, self.cluster_name, 'ipconf' + '-' + str(index), component_key) + network_interface.specification.subnet_name = subnet_name + network_interface.specification.use_public_ip = self.cluster_model.specification.cloud.use_public_ips + network_interface.specification.public_ip_name = public_ip_name + network_interface.specification.enable_accelerated_networking = vm_config.specification.network_interface.enable_accelerated_networking + return network_interface + + def get_public_ip(self, component_key, component_value, vm_config, index): + public_ip = self.get_config_or_default(self.docs, 'infrastructure/public-ip') + public_ip.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'pubip' + '-' + str(index), component_key) + public_ip.specification.allocation_method = vm_config.specification.network_interface.public_ip.allocation_method + public_ip.specification.idle_timeout_in_minutes = vm_config.specification.network_interface.public_ip.idle_timeout_in_minutes + public_ip.specification.sku = vm_config.specification.network_interface.public_ip.sku + return public_ip + + def get_vm(self, component_key, component_value, vm_config, network_interface_name, index): + vm = dict_to_objdict(deepcopy(vm_config)) vm.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vm' + '-' + str(index), component_key) vm.specification.admin_username = self.cluster_model.specification.admin_user.name + vm.specification.network_interface_name = network_interface_name + vm.specification.tags.append({'cluster': f'{self.cluster_prefix}-{self.cluster_name}'}) + vm.specification.tags.append({component_key: ''}) if vm.specification.os_type == 'linux': # For linux we dont need a PW since we only support SSH so just add something random. - vm.specification.admin_password = self.lnx_vm_pw - if vm.specification.os_type == 'windows': + vm.specification.admin_password = "NeverGonnaNeed!" + if vm_config.specification.os_type == 'windows': #TODO: We need PW or can we support SSH or something different on Windows? vm.specification.admin_password = 'TODO' pub_key_path = self.cluster_model.specification.admin_user.key_path + '.pub' diff --git a/core/src/epicli/cli/helpers/naming_helpers.py b/core/src/epicli/cli/helpers/naming_helpers.py index 9e6c5b3c0e..8052e1207a 100644 --- a/core/src/epicli/cli/helpers/naming_helpers.py +++ b/core/src/epicli/cli/helpers/naming_helpers.py @@ -7,13 +7,15 @@ def to_feature_name(role_name): def resource_name(prefix, cluster_name, resource_type, component=None): + name = '' if prefix == 'default': if component is None: - return '%s-%s' % (cluster_name.lower(), resource_type.lower()) + name = '%s-%s' % (cluster_name.lower(), resource_type.lower()) else: - return '%s-%s-%s' % (cluster_name.lower(), component.lower(), resource_type.lower()) + name = '%s-%s-%s' % (cluster_name.lower(), component.lower(), resource_type.lower()) else: if component is None: - return '%s-%s-%s' % (prefix.lower(), cluster_name.lower(), resource_type.lower()) + name = '%s-%s-%s' % (prefix.lower(), cluster_name.lower(), resource_type.lower()) else: - return '%s-%s-%s-%s' % (prefix.lower(), cluster_name.lower(), component.lower(), resource_type.lower()) + name = '%s-%s-%s-%s' % (prefix.lower(), cluster_name.lower(), component.lower(), resource_type.lower()) + return to_feature_name(name) diff --git a/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 b/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 index 6fbdc1d37e..421c56bf7e 100644 --- a/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 +++ b/core/src/epicli/data/aws/terraform/epiphany-cluster.j2 @@ -11,6 +11,7 @@ ##################################################### provider "aws" { + version = "=2.26" access_key = "{{ specification.cloud.credentials.key }}" secret_key = "{{ specification.cloud.credentials.secret }}" region = "{{ specification.cloud.region }}" diff --git a/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml b/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml new file mode 100644 index 0000000000..251d0b9ee4 --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml @@ -0,0 +1,13 @@ +kind: infrastructure/network-interface +version: 0.3.0 +title: "Network Interface Config" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + security_group_name: SET_BY_AUTOMATION + ip_configuration_name: SET_BY_AUTOMATION + subnet_name: SET_BY_AUTOMATION + use_public_ip: SET_BY_AUTOMATION + public_ip_name: SET_BY_AUTOMATION + enable_accelerated_networking: SET_BY_AUTOMATION \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/security-group.yml b/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml similarity index 52% rename from core/src/epicli/data/azure/defaults/infrastructure/security-group.yml rename to core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml index 8d42ccc94b..8bbca2698c 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/security-group.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml @@ -1,7 +1,8 @@ -kind: infrastructure/security-group +kind: infrastructure/network-security-group version: 0.3.0 title: "Security Group Config" provider: azure name: default specification: - name: SET_BY_AUTOMATION \ No newline at end of file + name: SET_BY_AUTOMATION + rules: [] \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml b/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml new file mode 100644 index 0000000000..0fde9dd74c --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml @@ -0,0 +1,10 @@ +kind: infrastructure/public-ip +version: 0.3.0 +title: "Public IP Config" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + allocation_method: SET_BY_AUTOMATION + idle_timeout_in_minutes: SET_BY_AUTOMATION + sku: SET_BY_AUTOMATION \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml b/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml new file mode 100644 index 0000000000..ab113fede2 --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml @@ -0,0 +1,9 @@ +kind: infrastructure/subnet-network-security-group-association +version: 0.3.0 +title: "Subnet Network Security Group Association" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + subnet_name: SET_BY_AUTOMATION + security_group_name: SET_BY_AUTOMATION diff --git a/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml index 1a6e324ee9..f2ace2cf73 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml @@ -6,4 +6,4 @@ name: default specification: name: SET_BY_AUTOMATION address_prefix: SET_BY_AUTOMATION - security_group_name: SET_BY_AUTOMATION + security_group_name: SET_BY_AUTOMATION \ No newline at end of file diff --git a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml index 82744194d8..d19dfff26b 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml @@ -8,6 +8,8 @@ specification: admin_username: SET_BY_AUTOMATION admin_password: SET_BY_AUTOMATION public_key: SET_BY_AUTOMATION + network_interface_name: SET_BY_AUTOMATION + tags: [] os_type: linux size: Standard_DS1_v2 storage_image_reference: @@ -22,39 +24,385 @@ specification: create_option: FromImage disk_size_gb: 30 managed_disk_type: Premium_LRS - security: [] + network_interface: + enable_accelerated_networking: false + private_ip: + public_ip: + allocation_method: Static + idle_timeout_in_minutes: 30 + sku: Standard + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "*" + destination_address_prefix: "*" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: load-balancer-machine +name: kubernetes-master-machine specification: - size: Standard_DS1_v2 + size: Standard_DS2_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: subnet-traffic + description: Allow subnet traffic + priority: 201 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.1.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: monitoring-traffic + description: Allow monitoring subnet traffic + priority: 203 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.4.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: node-subnet-traffic + description: Allow node subnet traffic + priority: 204 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.2.0/24" + destination_address_prefix: "0.0.0.0/0" + # - name: node2-subnet-traffic + # description: Allow node subnet traffic + # priority: 102 + # direction: Inbound + # access: Allow + # protocol: "*" + # source_port_range: "*" + # destination_from_port: 0 + # destination_to_port: 65536 + # destination_port_range: "0" + # source_address_prefix: "10.1.4.0/24" + # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: kubernetes-master-machine +name: kubernetes-node-machine specification: - size: Standard_DS2_v2 + size: Standard_DS1_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: subnet-traffic + description: Allow master subnet traffic + priority: 201 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.1.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: monitoring-traffic + description: Allow monitoring subnet traffic + priority: 203 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.4.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: node-subnet-traffic + description: Allow node subnet traffic + priority: 204 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.2.0/24" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: kubernetes-node-machine +name: kafka-machine specification: - size: Standard_DS1_v2 + size: Standard_DS2_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: kafka_exporter + description: Allow kafka exporter traffic + priority: 201 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9308" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: zookeeper1 + description: Allow Zookeeper 1 + priority: 202 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "3888" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: zookeeper2 + description: Allow Zookeeper 2 + priority: 203 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "2888" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: zookeeper_client_2181 + description: Allow Zookeeper Client + priority: 204 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "2181" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: zookeeper_client_9092 + description: Allow Zookeeper Client + priority: 205 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "9092" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: monitoring-traffic + description: Allow monitoring subnet traffic + priority: 206 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.4.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: kubernetes-traffic + description: Allow Kubernetes subnet traffic + priority: 207 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.1.0/24" + destination_address_prefix: "0.0.0.0/0" + #- name: kubernetes-traffic2 + # description: Allow Kubernetes subnet traffic + # priority: 208 + # direction: Inbound + # access: Allow + # protocol: "*" + # source_port_range: "*" + # destination_from_port: 0 + # destination_to_port: 65536 + # destination_port_range: "0" + # source_address_prefix: "10.1.2.0/24" + # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: kafka-machine +name: rabbit-machine specification: - size: Standard_DS2_v + size: Standard_DS2_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: rabbitmq + description: Allow rabbitmq traffic + priority: 201 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "5672" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 @@ -63,6 +411,122 @@ provider: azure name: monitoring-machine specification: size: Standard_DS1_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: prometheus + description: Allow connection to Prometheus + priority: 201 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9090" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: grafana + description: Allow connection to Grafana + priority: 202 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "3000" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" +--- +kind: infrastructure/virtual-machine +version: 0.3.0 +title: "Virtual Machine Infra" +provider: azure +name: postgresql-machine +specification: + size: Standard_DS1_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: kubernetes-traffic + description: Allow Kubernetes subnet traffic + priority: 202 + direction: Inbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_from_port: 0 + destination_to_port: 65536 + destination_port_range: "0" + source_address_prefix: "10.1.1.0/24" + destination_address_prefix: "0.0.0.0/0" + #- name: kubernetes-traffic2 + # description: Allow Kubernetes subnet traffic + # priority: 102 + # direction: Inbound + # access: Allow + # protocol: "*" + # source_port_range: "*" + # destination_from_port: 0 + # destination_to_port: 65536 + # destination_port_range: "0" + # source_address_prefix: "10.1.2.0/24" + # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 @@ -71,11 +535,115 @@ provider: azure name: logging-machine specification: size: Standard_DS1_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: Elastic + description: Allow Elastic + priority: 201 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "9200" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: Elastic2 + description: Allow Elastic + priority: 202 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "9300" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: Kibana + description: Allow Kibana + priority: 203 + direction: Inbound + access: Allow + protocol: "Tcp" + source_port_range: "*" + destination_port_range: "5601" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.3.0 title: "Virtual Machine Infra" provider: azure -name: postgresql-machine +name: load-balancer-machine specification: - size: Standard_DS1_v2 + size: Standard_DS1_v2 + security: + rules: + - name: ssh + description: Allow SSH + priority: 100 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "22" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: out + description: Allow out + priority: 101 + direction: Outbound + access: Allow + protocol: "*" + source_port_range: "*" + destination_port_range: "0" + source_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" + - name: node_exporter + description: Allow node_exporter traffic + priority: 200 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9100" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: haproxy_exporter + description: Allow haproxy_exporter traffic + priority: 201 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "9101" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 index faca2beeb6..7138f9bc89 100644 --- a/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 +++ b/core/src/epicli/data/azure/terraform/epiphany-cluster.j2 @@ -11,4 +11,5 @@ ##################################################### provider "azurerm" { + version = "=1.27" } diff --git a/core/src/epicli/data/azure/terraform/infrastructure/network-interface.j2 b/core/src/epicli/data/azure/terraform/infrastructure/network-interface.j2 new file mode 100644 index 0000000000..bb5574c901 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/network-interface.j2 @@ -0,0 +1,30 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_network_interface" "{{ specification.name }}" { + name = "{{ specification.name }}" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + network_security_group_id = "${azurerm_network_security_group.{{ specification.security_group_name }}.id}" + enable_accelerated_networking = "{{ specification.enable_accelerated_networking | lower }}" + + ip_configuration { + name = "{{ specification.ip_configuration_name }}" + subnet_id = "${azurerm_subnet.{{ specification.subnet_name }}.id}" + private_ip_address_allocation = "Dynamic" #TODO: Check if we need this configurable again and set the private_ip_address field. + {%- if specification.use_public_ip %} + public_ip_address_id = "${azurerm_public_ip.{{ specification.public_ip_name }}.id}" + {%- endif %} + } +} + + diff --git a/core/src/epicli/data/azure/terraform/infrastructure/network-security-group.j2 b/core/src/epicli/data/azure/terraform/infrastructure/network-security-group.j2 new file mode 100644 index 0000000000..5bfcc4d488 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/network-security-group.j2 @@ -0,0 +1,32 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_network_security_group" "{{ specification.name }}" { + name = "{{ specification.name }}" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + + {% for rule in specification.rules -%} + security_rule { + name = "{{ rule.name }}" + description = "{{ rule.description }}" + priority = {{ rule.priority }} + direction = "{{ rule.direction }}" + access = "{{ rule.access }}" + protocol = "{{ rule.protocol }}" + source_port_range = "{{ rule.source_port_range }}" + destination_port_range = "{{ rule.destination_port_range }}" + source_address_prefix = "{{ rule.source_address_prefix }}" + destination_address_prefix = "{{ rule.destination_address_prefix }}" + } + {% endfor -%} +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/public-ip.j2 b/core/src/epicli/data/azure/terraform/infrastructure/public-ip.j2 new file mode 100644 index 0000000000..c43a7788d7 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/public-ip.j2 @@ -0,0 +1,20 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### + +resource "azurerm_public_ip" "{{ specification.name }}" { + name = "{{ specification.name }}" + location = "${azurerm_resource_group.rg.location}" + resource_group_name = "${azurerm_resource_group.rg.name}" + allocation_method = "{{ specification.allocation_method }}" + idle_timeout_in_minutes = "{{ specification.idle_timeout_in_minutes }}" + sku = "{{ specification.sku }}" +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 b/core/src/epicli/data/azure/terraform/infrastructure/subnet-network-security-group-association.j2 similarity index 71% rename from core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 rename to core/src/epicli/data/azure/terraform/infrastructure/subnet-network-security-group-association.j2 index e312ad752b..e5c8923e03 100644 --- a/core/src/epicli/data/azure/terraform/infrastructure/security-group.j2 +++ b/core/src/epicli/data/azure/terraform/infrastructure/subnet-network-security-group-association.j2 @@ -10,8 +10,7 @@ # {{ specification.name }} ##################################################### -resource "azurerm_network_security_group" "{{ specification.name }}" { - name = "{{ specification.name }}" - location = "${azurerm_resource_group.rg.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" +resource "azurerm_subnet_network_security_group_association" "{{ specification.name }}" { + subnet_id = "${azurerm_subnet.{{ specification.subnet_name }}.id}" + network_security_group_id = "${azurerm_network_security_group.{{ specification.security_group_name }}.id}" } \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 b/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 index c1f54c52e7..31df83457e 100644 --- a/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 +++ b/core/src/epicli/data/azure/terraform/infrastructure/subnet.j2 @@ -13,7 +13,10 @@ resource "azurerm_subnet" "{{ specification.name }}" { name = "{{ specification.name }}" address_prefix = "{{ specification.address_prefix }}" + + #Deprecated but needed for now because of deadlock. + network_security_group_id = "${azurerm_network_security_group.{{ specification.security_group_name }}.id}" + resource_group_name = "${azurerm_resource_group.rg.name}" virtual_network_name = "${azurerm_virtual_network.vnet.name}" - network_security_group_id = "${azurerm_network_security_group.{{ specification.security_group_name}}.id}" } diff --git a/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 b/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 index b6738708b2..6bb7fe943c 100644 --- a/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 +++ b/core/src/epicli/data/azure/terraform/infrastructure/virtual-machine.j2 @@ -15,7 +15,7 @@ resource "azurerm_virtual_machine" "{{ specification.name }}" { location = "${azurerm_resource_group.rg.location}" resource_group_name = "${azurerm_resource_group.rg.name}" vm_size = "{{ specification.size }}" - network_interface_ids = [] #TODO + network_interface_ids = ["${azurerm_network_interface.{{ specification.network_interface_name }}.id}"] storage_image_reference { publisher = "{{ specification.storage_image_reference.publisher }}" @@ -61,9 +61,15 @@ resource "azurerm_virtual_machine" "{{ specification.name }}" { {%- endif %} } + tags = { + {%- for tag in specification.tags %} + {%- for tag_key, tag_value in tag.items() %} + {{ tag_key }} = "{{ tag_value }}" + {%- endfor %} + {%- endfor %} + } + #TODO: # availability_set_id - # network_interface_ids # storage_data_disk - # provisioners } diff --git a/core/src/epicli/data/azure/validation/infrastructure/security-group.yml b/core/src/epicli/data/azure/validation/infrastructure/network-interface.yml similarity index 100% rename from core/src/epicli/data/azure/validation/infrastructure/security-group.yml rename to core/src/epicli/data/azure/validation/infrastructure/network-interface.yml diff --git a/core/src/epicli/data/azure/validation/infrastructure/network-security-group.yml b/core/src/epicli/data/azure/validation/infrastructure/network-security-group.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/network-security-group.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/data/azure/validation/infrastructure/public-ip.yml b/core/src/epicli/data/azure/validation/infrastructure/public-ip.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/public-ip.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/data/azure/validation/infrastructure/subnet-network-security-group-association.yml b/core/src/epicli/data/azure/validation/infrastructure/subnet-network-security-group-association.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/subnet-network-security-group-association.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py index 7db3d4742c..3846547fd2 100644 --- a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py @@ -27,9 +27,9 @@ def test_get_security_group_should_set_proper_values_to_model(): cluster_model = get_cluster_model(cluster_name='TestCluster') builder = InfrastructureBuilder([cluster_model]) - actual = builder.get_security_group('component', 1) + actual = builder.get_network_security_group('component', [], 1) - assert actual.specification.name == 'prefix-testcluster-component-security-group-1' + assert actual.specification.name == 'prefix-testcluster-component-nsg-1' def test_get_subnet_should_set_proper_values_to_model(): @@ -40,14 +40,71 @@ def test_get_subnet_should_set_proper_values_to_model(): }) builder = InfrastructureBuilder([cluster_model]) - actual = builder.get_subnet(subnet_definition, 'component', 'prefix-testcluster-component-security-group-1', 1) + actual = builder.get_subnet(subnet_definition, 'component', 1) assert actual.specification.name == 'prefix-testcluster-component-subnet-1' assert actual.specification.address_prefix == subnet_definition['address_pool'] - assert actual.specification.security_group_name == 'prefix-testcluster-component-security-group-1' assert actual.specification.cluster_name == 'testcluster' +def test_get_subnet_network_security_group_association_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_subnet_network_security_group_association( + 'component', + 'prefix-testcluster-component-subnet-1', + 'prefix-testcluster-component-sg-1', + 1) + + assert actual.specification.name == 'prefix-testcluster-component-ssga-1' + assert actual.specification.subnet_name == 'prefix-testcluster-component-subnet-1' + assert actual.specification.security_group_name == 'prefix-testcluster-component-sg-1' + + + +def test_get_public_ip_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + component_value = dict_to_objdict({ + 'machine': 'kubernetes-master-machine' + }) + vm_config = builder.get_virtual_machine(component_value, cluster_model, []) + + actual = builder.get_public_ip('kubernetes_master', component_value, vm_config, 1) + + assert actual.specification.name == 'prefix-testcluster-kubernetes-master-pubip-1' + assert actual.specification.allocation_method == 'Static' + assert actual.specification.idle_timeout_in_minutes == 30 + assert actual.specification.sku == 'Standard' + + +def test_get_network_interface_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + component_value = dict_to_objdict({ + 'machine': 'kubernetes-master-machine' + }) + vm_config = builder.get_virtual_machine(component_value, cluster_model, []) + + actual = builder.get_network_interface( + 'kubernetes_master', + component_value, + vm_config, + 'prefix-testcluster-component-subnet-1', + 'prefix-testcluster-component-sg-1', + 'prefix-testcluster-kubernetes-master-pubip-1', + 1) + + assert actual.specification.name == 'prefix-testcluster-kubernetes-master-nic-1' + assert actual.specification.security_group_name == 'prefix-testcluster-component-sg-1' + assert actual.specification.ip_configuration_name == 'prefix-testcluster-kubernetes-master-ipconf-1' + assert actual.specification.subnet_name == 'prefix-testcluster-component-subnet-1' + assert actual.specification.use_public_ip == True + assert actual.specification.public_ip_name == 'prefix-testcluster-kubernetes-master-pubip-1' + assert actual.specification.enable_accelerated_networking == False + + def get_cluster_model(address_pool='10.22.0.0/22', cluster_name='EpiphanyTestCluster'): cluster_model = dict_to_objdict({ 'kind': 'epiphany-cluster', @@ -57,7 +114,8 @@ def get_cluster_model(address_pool='10.22.0.0/22', cluster_name='EpiphanyTestClu 'prefix': 'prefix', 'cloud': { 'region': 'West Europe', - 'vnet_address_pool': address_pool + 'vnet_address_pool': address_pool, + 'use_public_ips': True } } }) From 03f3054bd96856e2744a91f9b9c4ee2ad32d317d Mon Sep 17 00:00:00 2001 From: erzetpe Date: Tue, 10 Sep 2019 14:00:07 +0200 Subject: [PATCH 34/57] File generating hashes for directory (#477) * Item: #422 Desc: Add missing ports for prometheus and grafana * Item: #0000 Desc: File hash generator for directory * Item: #0000 Desc: Moved folder to new structure --- core/src/tools/file_hash_generator/Pipfile | 11 +++ .../file_hash_generator/directory_hash.py | 96 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 core/src/tools/file_hash_generator/Pipfile create mode 100644 core/src/tools/file_hash_generator/directory_hash.py diff --git a/core/src/tools/file_hash_generator/Pipfile b/core/src/tools/file_hash_generator/Pipfile new file mode 100644 index 0000000000..b723d0199f --- /dev/null +++ b/core/src/tools/file_hash_generator/Pipfile @@ -0,0 +1,11 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] + +[requires] +python_version = "3.7" diff --git a/core/src/tools/file_hash_generator/directory_hash.py b/core/src/tools/file_hash_generator/directory_hash.py new file mode 100644 index 0000000000..ba49bf0282 --- /dev/null +++ b/core/src/tools/file_hash_generator/directory_hash.py @@ -0,0 +1,96 @@ +import os +import hashlib +import logging +import argparse +import time + +BLOCK_SIZE = 65536 + + +def hash_factory(hash_algorithm): + if hash_algorithm == "sha256": + return hashlib.sha256() + + if hash_algorithm == "sha512": + return hashlib.sha512() + + raise NotImplementedError + + +def file_hash(file_path, hash_algorithm): + + hash_engine = hash_factory(hash_algorithm) + + with open(file_path, 'rb') as file: + buf = file.read(BLOCK_SIZE) + while len(buf) > 0: + hash_engine.update(buf) + buf = file.read(BLOCK_SIZE) + + return hash_engine.hexdigest() + + +def create_files_to_hash_list(packages_path): + files_to_hash = [] + + logging.info("Starting creating list of files to hash") + + for root, directory, files in os.walk(packages_path): + for file in files: + file_full_path = os.path.join(root, file) + if os.path.isfile(file_full_path): + files_to_hash.append(file_full_path) + + return files_to_hash + + +def write_files_with_hash_to_file(files_to_hash, output_file, hash_algorithm): + + logging.info(f"Writing hash ({hash_algorithm}) list to output file") + with open(output_file, "w") as dest_file: + + for file in files_to_hash: + hashed_value = file_hash(file, hash_algorithm) + logging.info(f"Filename: {file} - {hash_algorithm}: {hashed_value}") + dest_file.write(f"{hashed_value} {file}\n") + + +def parse_arguments(): + parser = argparse.ArgumentParser('Run hash function over directory.') + + parser.add_argument('-p', '--packages-directory', type=str, + help='path where packages to hash are stored') + parser.add_argument('-o', '--output', type=str, + help='file to which packages with hash will be written') + parser.add_argument('-a', '--algorithm', type=str, + help='hashing algorithm available: [ sha256, sha512]') + parser.add_argument('--debug', action='store_true', + help='debugging option') + + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + + arguments = parse_arguments() + + log_level = logging.DEBUG if arguments.debug else logging.INFO + + logging.basicConfig(level=log_level) + + logging.debug(arguments) + + logging.info("Starting hash program.") + + packages_path = arguments.packages_directory + output_file = arguments.output + hashing_algorithm = arguments.algorithm + + start_time = time.time() + + files_to_sha = create_files_to_hash_list(packages_path) + write_files_with_hash_to_file(files_to_sha, output_file, hashing_algorithm) + + logging.debug(f"Time of execution: {time.time() - start_time}") From 76d55a1c6930c5fc0985a5f981844fd7e43ff4d2 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 13 Sep 2019 13:54:02 +0200 Subject: [PATCH 35/57] Testruns (#506) - Added running of python unit tests via debug config in VSCode - Added running of serverspec tests via debug config in VSCode - Documentation --- core/src/epicli/.devcontainer/Dockerfile | 4 + core/src/epicli/.gitignore | 3 +- core/src/epicli/.vscode/launch.json | 22 ++++ core/src/epicli/run-tests.py | 47 ++++++++ core/src/epicli/run-tests.sh | 4 - core/src/epicli/tests/cli/conftest.py | 2 +- .../images/development/runserverspectests.png | 3 + .../images/development/rununittests.png | 3 + docs/home/DEVELOPMENT.md | 113 ++++++++++++------ 9 files changed, 157 insertions(+), 44 deletions(-) create mode 100644 core/src/epicli/run-tests.py delete mode 100755 core/src/epicli/run-tests.sh create mode 100644 docs/assets/images/development/runserverspectests.png create mode 100644 docs/assets/images/development/rununittests.png diff --git a/core/src/epicli/.devcontainer/Dockerfile b/core/src/epicli/.devcontainer/Dockerfile index 9de4bb890c..1823a833a5 100644 --- a/core/src/epicli/.devcontainer/Dockerfile +++ b/core/src/epicli/.devcontainer/Dockerfile @@ -11,6 +11,10 @@ RUN apt-get update \ && apt-get -y install git procps lsb-release gcc make musl-dev libffi-dev tar unzip \ + && apt-get -y install ruby-full \ + + && gem install serverspec rake rspec_junit_formatter \ + && pip --disable-pip-version-check --no-cache-dir install pylint \ && pip --disable-pip-version-check --no-cache-dir install pipenv \ diff --git a/core/src/epicli/.gitignore b/core/src/epicli/.gitignore index 090eebf267..ec7a9fe64d 100644 --- a/core/src/epicli/.gitignore +++ b/core/src/epicli/.gitignore @@ -123,7 +123,8 @@ dmypy.json # epicli specific external/ -tests_result/ +tests/serverspec-cli/results/ +tests/cli/results/ .terraform clusters .vscode diff --git a/core/src/epicli/.vscode/launch.json b/core/src/epicli/.vscode/launch.json index 571d43e0fd..cda814f208 100644 --- a/core/src/epicli/.vscode/launch.json +++ b/core/src/epicli/.vscode/launch.json @@ -14,6 +14,28 @@ "env": { "PYTHONPATH": "${workspaceFolder}" }, "console": "integratedTerminal", "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + }, + { + "name": "python unit tests", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/run-tests.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["python"] + }, + { + "name": "server spec tests", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/run-tests.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["spec", "-i", "${workspaceFolder}/PATH_TO_CLUSTER_INVENTORY", "-u", "ADMIN_USER", "-k", "${workspaceFolder}/PATH_TO_SSH_KEY"] } ] } \ No newline at end of file diff --git a/core/src/epicli/run-tests.py b/core/src/epicli/run-tests.py new file mode 100644 index 0000000000..60955279b9 --- /dev/null +++ b/core/src/epicli/run-tests.py @@ -0,0 +1,47 @@ +#!/usr/bin/env py +import sys +import argparse +import json +import os +import subprocess + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, + usage='''test []''', + formatter_class=argparse.RawDescriptionHelpFormatter) + + subparsers = parser.add_subparsers() + python_parser(subparsers) + spec_parser(subparsers) + + arg = parser.parse_args() + return arg.func(arg) + + +def python_parser(subparsers): + sub_parser = subparsers.add_parser('python', description='Runs the Epicli python unit tests') + + def run_python(args): + subprocess.call('mkdir -p tests/cli/results/ && python -m pytest ./tests/ --junit-xml=tests/cli/results/result.xml | tee tests/cli/results/result.txt', shell=True) + + sub_parser.set_defaults(func=run_python) + + +def spec_parser(subparsers): + sub_parser = subparsers.add_parser('spec', description='Runs the serverspec tests against an existing cluster') + sub_parser.add_argument('-i', '--inventory', dest='inventory', type=str, required=True, + help='The location of the inventory file of the cluster') + sub_parser.add_argument('-u', '--user', dest='user', type=str, required=True, + help='The admin user of the machines in the cluster') + sub_parser.add_argument('-k', '--key', dest='key', type=str, required=True, + help='The SSH key for the machines in the cluster') + + def run_spec(args): + subprocess.call(f'cd tests/serverspec-cli && rake inventory="{args.inventory}" user={args.user} keypath="{args.key}" spec:all', shell=True) + + sub_parser.set_defaults(func=run_spec) + + +if __name__ == '__main__': + exit(main()) diff --git a/core/src/epicli/run-tests.sh b/core/src/epicli/run-tests.sh deleted file mode 100755 index 8bd07f2b7b..0000000000 --- a/core/src/epicli/run-tests.sh +++ /dev/null @@ -1,4 +0,0 @@ -# Run the python test for Epicli -mkdir -p tests_result -python -m pytest ./tests/ --junit-xml=tests_result/result.xml | tee tests_result/result.txt -echo "Done running tests. See tests_result/result.txt" \ No newline at end of file diff --git a/core/src/epicli/tests/cli/conftest.py b/core/src/epicli/tests/cli/conftest.py index e7c172799b..b4963f09e1 100644 --- a/core/src/epicli/tests/cli/conftest.py +++ b/core/src/epicli/tests/cli/conftest.py @@ -7,7 +7,7 @@ def pytest_configure(config): This hook is called for every plugin and initial conftest file after command line options have been parsed. """ - Config().output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../tests_result/') + Config().output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '/results/') def pytest_sessionstart(session): diff --git a/docs/assets/images/development/runserverspectests.png b/docs/assets/images/development/runserverspectests.png new file mode 100644 index 0000000000..40c00addd6 --- /dev/null +++ b/docs/assets/images/development/runserverspectests.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d393809f6cf76de0aa0e4697b599c598488c06579f2cabf72c12baf6c34abb02 +size 2224 diff --git a/docs/assets/images/development/rununittests.png b/docs/assets/images/development/rununittests.png new file mode 100644 index 0000000000..4a264f798b --- /dev/null +++ b/docs/assets/images/development/rununittests.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6014db9b0c9be736acf6e4b21ab14cd8a4908854e8af1147b0f8522e06460dcf +size 1852 diff --git a/docs/home/DEVELOPMENT.md b/docs/home/DEVELOPMENT.md index 07bdb53a53..2779789793 100644 --- a/docs/home/DEVELOPMENT.md +++ b/docs/home/DEVELOPMENT.md @@ -9,6 +9,7 @@ - [Note for Windows users](#note-for-Windows-users) - [Running and debugging](#running-and-debugging) - [Running unit tests](#running-unit-tests) +- [Running serverspec tests](#running-serverspec-tests) @@ -84,48 +85,52 @@ For debugging, open the VSCode's Debug tab: By default there is one launch configuration called ```epicli```. This launch configuration can be found in ```/epiphany/core/src/epicli/.vscode/``` and looks like this: ```json - "configurations": [ - { - "name": "epicli", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/cli/epicli.py", - "cwd": "${workspaceFolder}", - "pythonPath": "${config:python.pythonPath}", - "env": { "PYTHONPATH": "${workspaceFolder}" }, - "console": "integratedTerminal", - "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] - } - ] + ... + + { + "name": "epicli", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + } + + ... ``` You can copy this configuration and change values (like below) to create different ones to suite your needs: ```json - "configurations": [ - { - "name": "epicli", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/cli/epicli.py", - "cwd": "${workspaceFolder}", - "pythonPath": "${config:python.pythonPath}", - "env": { "PYTHONPATH": "${workspaceFolder}" }, - "console": "integratedTerminal", - "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] - }, - { - "name": "epicli show version", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/cli/epicli.py", - "cwd": "${workspaceFolder}", - "pythonPath": "${config:python.pythonPath}", - "env": { "PYTHONPATH": "${workspaceFolder}" }, - "console": "integratedTerminal", - "args": ["--version"] - } - ] + ... + + { + "name": "epicli", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["apply", "-f", "${workspaceFolder}/PATH_TO_YOUR_DATA_YAML"] + }, + { + "name": "epicli show version", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/cli/epicli.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["--version"] + } + + ... ``` In the ```args``` field you can pass an array of the arguments that you want epicli to run with. @@ -136,10 +141,42 @@ To run a configuration, select it and press the run button: For more information about debugging in VSCode, go [here](https://code.visualstudio.com/docs/editor/debugging). -## Running unit tests +## Running Python unit tests The standard Python test runner fails to discover the tests so we use the ```Python Test Explorer``` extension. To run the unit tests, open the VSCode's Test tab and press the run button: ![unittests](../assets/images/development/unittests.png) See the [Python Test Explorer](https://marketplace.visualstudio.com/items?itemName=LittleFoxTeam.vscode-python-test-adapter) extension page on how to debug and run individual tests. + +You can also run the Python unit tests from a launch configuration called ```epicli``` + +![rununittests](../assets/images/development/rununittests.png) + +## Running serverspec tests + +We maintain a set of serverspec tests that can be run to verify if a cluster is functioning properly. While it might not cover all cases at this point it is a good place to start. + +There is one launch configuration called ```server spec tests```. This launch configuration can be found in ```/epiphany/core/src/epicli/.vscode/``` and looks like this: + + ```json + ... + + { + "name": "server spec tests", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/run-tests.py", + "cwd": "${workspaceFolder}", + "pythonPath": "${config:python.pythonPath}", + "env": { "PYTHONPATH": "${workspaceFolder}" }, + "console": "integratedTerminal", + "args": ["spec", "-i", "${workspaceFolder}/PATH_TO_CLUSTER_INVENTORY", "-u", "ADMIN_USER", "-k", "${workspaceFolder}/PATH_TO_SSH_KEY"] + } + + ... + ``` + +To run the serverspec tests against a given cluster change the ```args``` field to point to the cluster inventory, admin username and the propper SSH key. Then the run from the run tab: + +![runserverspectests](../assets/images/development/runserverspectests.png) From 3cf419709870f46477385a74381d4e0648475bac Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 13 Sep 2019 14:16:12 +0200 Subject: [PATCH 36/57] Release prep part 1 (#501) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * Preparation for release. --- CHANGELOG-0.4.md | 25 + CHANGELOG.md | 8 +- core/manifest.yaml | 2 +- core/src/epicli/Dockerfile | 2 +- core/src/epicli/cli/licenses.py | 1832 +++++++++++++++-- core/src/epicli/cli/version.py | 2 +- .../configuration/minimal-cluster-config.yml | 2 +- .../configuration/minimal-cluster-config.yml | 2 +- .../infrastructure/default-security-group.yml | 2 +- .../defaults/infrastructure/efs-storage.yml | 2 +- .../infrastructure/internet-gateway.yml | 2 +- .../infrastructure/launch-configuration.yml | 2 +- .../defaults/infrastructure/public-key.yml | 2 +- .../infrastructure/resource-group.yml | 2 +- .../route-table-association.yml | 2 +- .../defaults/infrastructure/route-table.yml | 2 +- .../infrastructure/security-group-rule.yml | 2 +- .../infrastructure/security-group.yml | 2 +- .../aws/defaults/infrastructure/subnet.yml | 2 +- .../infrastructure/virtual-machine.yml | 28 +- .../data/aws/defaults/infrastructure/vpc.yml | 2 +- .../configuration/minimal-cluster-config.yml | 2 +- .../infrastructure/network-interface.yml | 2 +- .../infrastructure/network-security-group.yml | 2 +- .../defaults/infrastructure/public-ip.yml | 2 +- .../infrastructure/resource-group.yml | 2 +- ...net-network-security-group-association.yml | 2 +- .../azure/defaults/infrastructure/subnet.yml | 2 +- .../infrastructure/virtual-machine.yml | 18 +- .../azure/defaults/infrastructure/vnet.yml | 2 +- .../defaults/configuration/applications.yml | 2 +- .../configuration/elasticsearch-curator.yml | 2 +- .../defaults/configuration/elasticsearch.yml | 2 +- .../configuration/feature-mapping.yml | 2 +- .../defaults/configuration/filebeat.yml | 2 +- .../common/defaults/configuration/grafana.yml | 2 +- .../configuration/haproxy-exporter.yml | 2 +- .../common/defaults/configuration/haproxy.yml | 2 +- .../defaults/configuration/jmx-exporter.yml | 2 +- .../defaults/configuration/kafka-exporter.yml | 2 +- .../common/defaults/configuration/kafka.yml | 2 +- .../common/defaults/configuration/kibana.yml | 2 +- .../configuration/kubernetes-master.yml | 2 +- .../configuration/kubernetes-node.yml | 2 +- .../defaults/configuration/node-exporter.yml | 2 +- .../defaults/configuration/postgresql.yml | 2 +- .../defaults/configuration/prometheus.yml | 2 +- .../defaults/configuration/rabbitmq.yml | 2 +- .../defaults/configuration/zookeeper.yml | 2 +- .../data/common/defaults/epiphany-cluster.yml | 2 +- .../defaults/infrastructure/machine.yml | 2 +- .../common/validation/core/definitions.yml | 4 +- core/src/epicli/gen-licenses.py | 33 +- core/src/epicli/prepare-bds.bat | 2 +- core/src/epicli/prepare-bds.sh | 2 +- core/version.sh | 2 +- docs/home/SECURITY.md | 7 +- docs/home/TESTING.md | 8 +- 58 files changed, 1851 insertions(+), 210 deletions(-) create mode 100644 CHANGELOG-0.4.md diff --git a/CHANGELOG-0.4.md b/CHANGELOG-0.4.md new file mode 100644 index 0000000000..f1f32af93a --- /dev/null +++ b/CHANGELOG-0.4.md @@ -0,0 +1,25 @@ +# Changelog 0.4 + +## [0.4.0] 2019-09-30 + +### Added + +- Offline installation +- Azure cluster deployments with Epicli +- Delete commands to remove clusters from cloud providers (AWS, Azure) +- Devcontainer for Epicli development using VSCode +- Debug flag for Epicli + +### Changed + +- Various improvements in Epicli +- Documentation cleanup and updates + +### Fixed + +- [#407](https://github.com/epiphany-platform/epiphany/issues/407) - Deployment/Application role fails because Kubernetes cluster is not ready after reboot. +- [#410](https://github.com/epiphany-platform/epiphany/issues/410) - Node_exporter ports are not present in defaults resulting in Prometheus not beeing able to scrape data with minimal cluster data.yaml. + +### Known issues + +- \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 341b42f495..eaa332146d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,16 @@ Reference for actual cluster component versions can be found [here](docs/home/CO ## Current release -### 0.3.x +### 0.4.x -- [CHANGELOG-0.3.0](./CHANGELOG-0.3.md#030-2019-07-31) +- [CHANGELOG-0.4.0](./CHANGELOG-0.4.md#040-2019-09-30) ## Older releases +### 0.3.x + +- [CHANGELOG-0.3.0](./CHANGELOG-0.3.md#030-2019-07-31) + ### 0.2.x - [CHANGELOG-0.2.3](./CHANGELOG-0.2.md#023-2019-05-20) diff --git a/core/manifest.yaml b/core/manifest.yaml index dea33bf9f3..eb8f74dbbc 100644 --- a/core/manifest.yaml +++ b/core/manifest.yaml @@ -3,7 +3,7 @@ # This data is for the core of Epiphany and not the data for a given environment. name: Epiphany -version: 0.3.0 +version: 0.4.0 # Set the proxy info up if your environment requires it. This is sometimes the case for on-premise builds/installs proxy: diff --git a/core/src/epicli/Dockerfile b/core/src/epicli/Dockerfile index 996b737316..7e9b476691 100644 --- a/core/src/epicli/Dockerfile +++ b/core/src/epicli/Dockerfile @@ -1,7 +1,7 @@ FROM python:3.7-alpine ENV DOCKER_CLI Yes -ENV EPICLI_VERSION 0.3.0 +ENV EPICLI_VERSION 0.4.0 COPY /dist/ /epicli WORKDIR /epicli diff --git a/core/src/epicli/cli/licenses.py b/core/src/epicli/cli/licenses.py index 5704f090e6..d43d11f71e 100644 --- a/core/src/epicli/cli/licenses.py +++ b/core/src/epicli/cli/licenses.py @@ -4,41 +4,44 @@ LICENSES = [ { - "Name": "terraform-binary", - "Version": "0.11.11.post1", - "Summary": "Python wrapper for Terraform", - "Home-page": "https://github.com/sourcelair/terraform-binary/", - "Author": "Paris Kasidiaris", + "Name": "azure-storage-nspkg", + "Version": "3.1.0", + "Summary": "Microsoft Azure Storage Namespace Package [Internal]", + "Home-page": "https://github.com/Azure/azure-storage-python", + "Author": "Microsoft Corporation", "License": "MIT License", - "License repo": "The MIT License (MIT)\n\nCopyright (c) SourceLair Private Company\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2017 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "botocore", - "Version": "1.12.182", - "Summary": "Low-level, data-driven core of boto 3.", - "Home-page": "https://github.com/boto/botocore", - "Author": "Amazon Web Services", - "License": "Apache License 2.0", - "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n", - "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + "Name": "python-json-logger", + "Version": "0.1.11", + "Summary": "A python library adding a json log formatter", + "Home-page": "http://github.com/madzak/python-json-logger", + "Author": "Zakaria Zajac", + "License": "BSD 2-Clause \"Simplified\" License", + "License repo": "Copyright (c) 2011, Zakaria Zajac \nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 2-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { - "Name": "pycparser", - "Version": "2.19", - "Summary": "C parser in Python", - "Home-page": "https://github.com/eliben/pycparser", - "Author": "Eli Bendersky", - "License": "Other", - "License repo": "pycparser -- A C parser in Python\n\nCopyright (c) 2008-2017, Eli Bendersky\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this \n list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, \n this list of conditions and the following disclaimer in the documentation \n and/or other materials provided with the distribution.\n* Neither the name of Eli Bendersky nor the names of its contributors may \n be used to endorse or promote products derived from this software without \n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND \nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE \nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR \nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE \nGOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT \nOF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "Name": "azure-mgmt-sqlvirtualmachine", + "Version": "0.3.0", + "Summary": "Microsoft Azure SQL Virtual Machine Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "ansible", - "Version": "2.8.1", - "Summary": "Radically simple IT automation", - "Home-page": "https://ansible.com/", - "Author": "Ansible, Inc.", - "License": "GPLv3+" + "Name": "azure-mgmt-devtestlabs", + "Version": "2.2.0", + "Summary": "Microsoft Azure DevTestLabs Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { "Name": "MarkupSafe", @@ -49,15 +52,201 @@ "License": "BSD-3-Clause" }, { - "Name": "boto3", - "Version": "1.9.182", - "Summary": "The AWS SDK for Python", - "Home-page": "https://github.com/boto/boto3", - "Author": "Amazon Web Services", + "Name": "PyYAML", + "Version": "5.1.2", + "Summary": "YAML parser and emitter for Python", + "Home-page": "https://github.com/yaml/pyyaml", + "Author": "Kirill Simonov", + "License": "MIT License", + "License repo": "Copyright (c) 2017-2019 Ingy d\u00f6t Net\nCopyright (c) 2006-2016 Kirill Simonov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-privatedns", + "Version": "1.0.2", + "Summary": "Microsoft Azure Command-Line Tools Network PrivateDns Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-sql", + "Version": "0.12.0", + "Summary": "Microsoft Azure SQL Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "jsonschema", + "Version": "3.0.2", + "Summary": "An implementation of JSON Schema validation for Python", + "Home-page": "https://github.com/Julian/jsonschema", + "Author": "Julian Berman", + "License": "MIT License", + "License repo": "Copyright (c) 2013 Julian Berman\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-deploymentmanager", + "Version": "0.1.1", + "Summary": "Microsoft Azure Command-Line Tools Deployment Manager Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "python-dateutil", + "Version": "2.8.0", + "Summary": "Extensions to the standard Python datetime module", + "Home-page": "https://dateutil.readthedocs.io", + "Author": "Gustavo Niemeyer", + "License": "Dual License" + }, + { + "Name": "xmltodict", + "Version": "0.12.0", + "Summary": "Makes working with XML feel like you are working with JSON", + "Home-page": "https://github.com/martinblech/xmltodict", + "Author": "Martin Blech", + "License": "MIT License", + "License repo": "Copyright (C) 2012 Martin Blech and individual contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-cosmosdb", + "Version": "0.6.1", + "Summary": "Microsoft Azure Cosmos DB Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "idna", + "Version": "2.8", + "Summary": "Internationalized Domain Names in Applications (IDNA)", + "Home-page": "https://github.com/kjd/idna", + "Author": "Kim Davies", + "License": "Other", + "License repo": "License\n-------\n\nCopyright (c) 2013-2018, Kim Davies. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n#. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n#. Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided with\n the distribution.\n\n#. Neither the name of the copyright holder nor the names of the \n contributors may be used to endorse or promote products derived \n from this software without specific prior written permission.\n\n#. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS \"AS IS\" AND ANY\n EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR \n CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\n USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n DAMAGE.\n\nPortions of the codec implementation and unit tests are derived from the\nPython standard library, which carries the `Python Software Foundation\nLicense `_:\n\n Copyright (c) 2001-2014 Python Software Foundation; All Rights Reserved\n\nPortions of the unit tests are derived from the Unicode standard, which \nis subject to the Unicode, Inc. License Agreement:\n\n Copyright (c) 1991-2014 Unicode, Inc. All rights reserved.\n Distributed under the Terms of Use in \n .\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of the Unicode data files and any associated documentation\n (the \"Data Files\") or Unicode software and any associated documentation\n (the \"Software\") to deal in the Data Files or Software\n without restriction, including without limitation the rights to use,\n copy, modify, merge, publish, distribute, and/or sell copies of\n the Data Files or Software, and to permit persons to whom the Data Files\n or Software are furnished to do so, provided that\n \n (a) this copyright and permission notice appear with all copies \n of the Data Files or Software,\n\n (b) this copyright and permission notice appear in associated \n documentation, and\n\n (c) there is clear notice in each modified Data File or in the Software\n as well as in the documentation associated with the Data File(s) or\n Software that the data or software has been modified.\n\n THE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF\n ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT OF THIRD PARTY RIGHTS.\n IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS\n NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL\n DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n PERFORMANCE OF THE DATA FILES OR SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder\n shall not be used in advertising or otherwise to promote the sale,\n use or other dealings in these Data Files or Software without prior\n written authorization of the copyright holder.\n" + }, + { + "Name": "azure-cli-find", + "Version": "0.3.4", + "Summary": "Intelligent querying for CLI Example information.", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-batchai", + "Version": "0.4.10", + "Summary": "Microsoft Azure Batch AI Client Command-Line Tools", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-iothubprovisioningservices", + "Version": "0.2.0", + "Summary": "Microsoft Azure IoTHub Provisioning Services Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "requests", + "Version": "2.22.0", + "Summary": "Python HTTP for Humans.", + "Home-page": "http://python-requests.org", + "Author": "Kenneth Reitz", + "License": "Apache 2.0" + }, + { + "Name": "azure-common", + "Version": "1.1.23", + "Summary": "Microsoft Azure Client Library for Python (Common)", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-appservice", + "Version": "0.2.21", + "Summary": "Microsoft Azure Command-Line Tools AppService Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-command-modules-nspkg", + "Version": "2.0.2", + "Summary": "Microsoft Azure CLI Command Modules Namespace Package", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "pycparser", + "Version": "2.19", + "Summary": "C parser in Python", + "Home-page": "https://github.com/eliben/pycparser", + "Author": "Eli Bendersky", + "License": "Other", + "License repo": "pycparser -- A C parser in Python\n\nCopyright (c) 2008-2017, Eli Bendersky\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this \n list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, \n this list of conditions and the following disclaimer in the documentation \n and/or other materials provided with the distribution.\n* Neither the name of Eli Bendersky nor the names of its contributors may \n be used to endorse or promote products derived from this software without \n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND \nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE \nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR \nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE \nGOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT \nOF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "terraform-bin", + "Version": "1.0.1", + "Summary": "UNKNOWN", + "Home-page": "https://github.com/epiphany-platform/terraform-bin", + "Author": "Epiphany Team", "License": "Apache License 2.0", - "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2019 ABB. All rights reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.", "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, + { + "Name": "azure-mgmt-cdn", + "Version": "3.1.0", + "Summary": "Microsoft Azure CDN Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-dns", + "Version": "2.1.0", + "Summary": "Microsoft Azure DNS Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "humanfriendly", + "Version": "4.18", + "Summary": "Human friendly output for text interfaces using Python", + "Home-page": "https://humanfriendly.readthedocs.io", + "Author": "Peter Odding", + "License": "MIT" + }, { "Name": "asn1crypto", "Version": "0.24.0", @@ -69,24 +258,12 @@ "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "PyYAML", - "Version": "5.1.1", - "Summary": "YAML parser and emitter for Python", - "Home-page": "https://github.com/yaml/pyyaml", - "Author": "Kirill Simonov", - "License": "MIT License", - "License repo": "Copyright (c) 2017-2019 Ingy d\u00f6t Net\nCopyright (c) 2006-2016 Kirill Simonov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", - "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "Name": "python-json-logger", - "Version": "0.1.11", - "Summary": "A python library adding a json log formatter", - "Home-page": "http://github.com/madzak/python-json-logger", - "Author": "Zakaria Zajac", - "License": "BSD 2-Clause \"Simplified\" License", - "License repo": "Copyright (c) 2011, Zakaria Zajac \nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", - "License text": "BSD 2-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "Name": "isodate", + "Version": "0.6.0", + "Summary": "An ISO 8601 date/time/duration parser and formatter", + "Home-page": "https://github.com/gweis/isodate/", + "Author": "Gerhard Weis", + "License": "BSD" }, { "Name": "urllib3", @@ -97,101 +274,1524 @@ "License": "MIT" }, { - "Name": "cryptography", - "Version": "2.7", - "Summary": "cryptography is a package which provides cryptographic recipes and primitives to Python developers.", - "Home-page": "https://github.com/pyca/cryptography", - "Author": "The cryptography developers", + "Name": "knack", + "Version": "0.6.3", + "Summary": "A Command-Line Interface framework", + "Home-page": "https://github.com/microsoft/knack", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": " MIT License\n\n Copyright (c) Microsoft Corporation. All rights reserved.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-kusto", + "Version": "0.2.3", + "Summary": "Microsoft Azure Command-Line Tools KUSTO Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", "License": "Other", - "License repo": "This software is made available under the terms of *either* of the licenses\nfound in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made\nunder the terms of *both* these licenses.\n\nThe code used in the OpenSSL locking callback and OS random engine is derived\nfrom CPython, and is licensed under the terms of the PSF License Agreement.\n" + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "jsonschema", - "Version": "3.0.1", - "Summary": "An implementation of JSON Schema validation for Python", - "Home-page": "https://github.com/Julian/jsonschema", - "Author": "Julian Berman", + "Name": "azure-cli-acr", + "Version": "2.2.9", + "Summary": "Microsoft Azure Command-Line Tools ACR Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-storage-common", + "Version": "1.4.2", + "Summary": "Microsoft Azure Storage Common Client Library for Python", + "Home-page": "https://github.com/Azure/azure-storage-python", + "Author": "Microsoft Corporation", "License": "MIT License", - "License repo": "Copyright (c) 2013 Julian Berman\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2017 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "s3transfer", + "Name": "azure-mgmt-msi", + "Version": "0.2.0", + "Summary": "Microsoft Azure MSI Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-redis", + "Version": "0.4.4", + "Summary": "Microsoft Azure Command-Line Tools Redis Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-ams", + "Version": "0.4.7", + "Summary": "Microsoft Azure Command-Line Tools AMS Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-privatedns", + "Version": "0.1.0", + "Summary": "Microsoft Azure DNS Private Zones Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-hdinsight", "Version": "0.2.1", - "Summary": "An Amazon S3 Transfer Manager", - "Home-page": "https://github.com/boto/s3transfer", - "Author": "Amazon Web Services", + "Summary": "Microsoft Azure HDInsight Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-imagebuilder", + "Version": "0.2.1", + "Summary": "Microsoft Azure Image Builder Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "pyperclip", + "Version": "1.7.0", + "Summary": "A cross-platform clipboard module for Python. (Only handles plain text for now.)", + "Home-page": "https://github.com/asweigart/pyperclip", + "Author": "Al Sweigart", + "License": "BSD 3-Clause \"New\" or \"Revised\" License", + "License repo": "Copyright (c) 2014, Al Sweigart\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the {organization} nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 3-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "websocket-client", + "Version": "0.56.0", + "Summary": "WebSocket client for Python. hybi13 is supported.", + "Home-page": "https://github.com/websocket-client/websocket-client.git", + "Author": "liris", + "License": "BSD" + }, + { + "Name": "argcomplete", + "Version": "1.10.0", + "Summary": "Bash tab completion for argparse", + "Home-page": "https://github.com/kislyuk/argcomplete", + "Author": "Andrey Kislyuk", "License": "Apache License 2.0", - "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n", "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { - "Name": "cffi", - "Version": "1.12.3", - "Summary": "Foreign Function Interface for Python calling C code.", - "Home-page": "http://cffi.readthedocs.org", - "Author": "Armin Rigo, Maciej Fijalkowski", - "License": "MIT" + "Name": "azure-mgmt-security", + "Version": "0.1.0", + "Summary": "Microsoft Azure Secutiry Center Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "jmespath", - "Version": "0.9.4", - "Summary": "JSON Matching Expressions", - "Home-page": "https://github.com/jmespath/jmespath.py", - "Author": "James Saryerwinnie", + "Name": "azure-cli-configure", + "Version": "2.0.24", + "Summary": "Microsoft Azure Command-Line Tools Configure Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", "License": "Other", - "License repo": "Copyright (c) 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish, dis-\ntribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the fol-\nlowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-\nITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n" + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "python-dateutil", - "Version": "2.8.0", - "Summary": "Extensions to the standard Python datetime module", - "Home-page": "https://dateutil.readthedocs.io", - "Author": "Gustavo Niemeyer", - "License": "Dual License" + "Name": "azure-cli-vm", + "Version": "2.2.23", + "Summary": "Microsoft Azure Command-Line Tools VM Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "pyrsistent", - "Version": "0.15.2", - "Summary": "Persistent/Functional/Immutable data structures", - "Home-page": "http://github.com/tobgu/pyrsistent/", - "Author": "Tobias Gustafsson", + "Name": "azure-mgmt-keyvault", + "Version": "1.1.0", + "Summary": "Microsoft Azure Key Vault Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", "License": "MIT License", - "License repo": "Copyright (c) 2019 Tobias Gustafsson\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "docutils", - "Version": "0.14", - "Summary": "Docutils -- Python Documentation Utilities", - "Home-page": "http://docutils.sourceforge.net/", - "Author": "docutils-develop list", - "License": "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)" + "Name": "azure-cli-dla", + "Version": "0.2.6", + "Summary": "Microsoft Azure Command-Line Tools Data Lake Analytics Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "Jinja2", - "Version": "2.10.1", - "Summary": "A small but fast and easy to use stand-alone template engine written in pure python.", - "Home-page": "http://jinja.pocoo.org/", - "Author": "Armin Ronacher", - "License": "BSD" + "Name": "azure-mgmt-loganalytics", + "Version": "0.2.0", + "Summary": "Microsoft Azure Log Analytics Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "attrs", - "Version": "19.1.0", - "Summary": "Classes Without Boilerplate", - "Home-page": "https://www.attrs.org/", - "Author": "Hynek Schlawack", - "License": "MIT" + "Name": "azure-mgmt-nspkg", + "Version": "3.0.2", + "Summary": "Microsoft Azure Resource Management Namespace Package [Internal]", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, { - "Name": "six", - "Version": "1.12.0", - "Summary": "Python 2 and 3 compatibility utilities", - "Home-page": "https://github.com/benjaminp/six", - "Author": "Benjamin Peterson", + "Name": "azure-cli-eventgrid", + "Version": "0.2.4", + "Summary": "Microsoft Azure Command-Line Tools EventGrid Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-applicationinsights", + "Version": "0.1.1", + "Summary": "Microsoft Azure Application Insights Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", "License": "MIT License", - "License repo": "Copyright (c) 2010-2019 Benjamin Peterson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "skopeo-bin", + "Version": "1.0.2", + "Summary": "UNKNOWN", + "Home-page": "https://github.com/epiphany-platform/skopeo-bin", + "Author": "Epiphany Team", + "License": "Apache License 2.0", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2019 ABB. All rights reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "requests-oauthlib", + "Version": "1.2.0", + "Summary": "OAuthlib authentication support for Requests.", + "Home-page": "https://github.com/requests/requests-oauthlib", + "Author": "Kenneth Reitz", + "License": "ISC License", + "License repo": "ISC License\n\nCopyright (c) 2014 Kenneth Reitz.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n", + "License text": "ISC License\n\nCopyright (c) [year], [fullname]\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" + }, + { + "Name": "azure-cli-eventhubs", + "Version": "0.3.7", + "Summary": "Microsoft Azure Command-Line Tools Event Hubs Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-feedback", + "Version": "2.2.1", + "Summary": "Microsoft Azure Command-Line Tools Feedback Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-datalake-store", + "Version": "0.0.39", + "Summary": "Azure Data Lake Store Filesystem Client Library for Python", + "Home-page": "https://github.com/Azure/azure-data-lake-store-python", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "\ufeffThe MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-reservations", + "Version": "0.4.3", + "Summary": "Microsoft Azure Command-Line Tools Reservations Command Module", + "Home-page": "https://github.com/azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "cryptography", + "Version": "2.7", + "Summary": "cryptography is a package which provides cryptographic recipes and primitives to Python developers.", + "Home-page": "https://github.com/pyca/cryptography", + "Author": "The cryptography developers", + "License": "Other", + "License repo": "This software is made available under the terms of *either* of the licenses\nfound in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made\nunder the terms of *both* these licenses.\n\nThe code used in the OpenSSL locking callback and OS random engine is derived\nfrom CPython, and is licensed under the terms of the PSF License Agreement.\n" + }, + { + "Name": "azure-mgmt-datalake-analytics", + "Version": "0.2.1", + "Summary": "Microsoft Azure Data Lake Analytics Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "fabric", + "Version": "2.5.0", + "Summary": "High level SSH command execution", + "Home-page": "http://fabfile.org", + "Author": "Jeff Forcier", + "License": "BSD" + }, + { + "Name": "jmespath", + "Version": "0.9.4", + "Summary": "JSON Matching Expressions", + "Home-page": "https://github.com/jmespath/jmespath.py", + "Author": "James Saryerwinnie", + "License": "Other", + "License repo": "Copyright (c) 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish, dis-\ntribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the fol-\nlowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-\nITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n" + }, + { + "Name": "azure-cli-search", + "Version": "0.1.2", + "Summary": "Microsoft Azure Command-Line Tools Search Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-advisor", + "Version": "2.0.1", + "Summary": "Microsoft Azure Command-Line Tools Advisor Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-storage", + "Version": "3.3.0", + "Summary": "Microsoft Azure Storage Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "antlr4-python3-runtime", + "Version": "4.7.2", + "Summary": "ANTLR 4.7.2 runtime for Python 3.6.3", + "Home-page": "http://www.antlr.org", + "Author": "Eric Vergnaud, Terence Parr, Sam Harwell", + "License": "BSD" + }, + { + "Name": "azure-mgmt-eventgrid", + "Version": "2.2.0", + "Summary": "Microsoft Azure EventGrid Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "vsts", + "Version": "0.1.25", + "Summary": "Python wrapper around the VSTS APIs", + "Home-page": "https://github.com/Microsoft/vsts-python-api", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": " MIT License\n\n Copyright (c) Microsoft Corporation. All rights reserved.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-consumption", + "Version": "0.4.4", + "Summary": "Microsoft Azure Command-Line Tools Consumption Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-cosmosdb", + "Version": "0.2.11", + "Summary": "Microsoft Azure Command-Line Tools Cosmos DB Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-resource", + "Version": "2.1.0", + "Summary": "Microsoft Azure Resource Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-interactive", + "Version": "0.4.5", + "Summary": "Microsoft Azure Command-Line Interactive Shell", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-eventhub", + "Version": "2.6.0", + "Summary": "Microsoft Azure EventHub Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "chardet", + "Version": "3.0.4", + "Summary": "Universal encoding detector for Python 2 and 3", + "Home-page": "https://github.com/chardet/chardet", + "Author": "Daniel Blanchard", + "License": "GNU Lesser General Public License v2.1", + "License repo": "\t\t GNU LESSER GENERAL PUBLIC LICENSE\n\t\t Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL. It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n\t\t\t Preamble\n\n The licenses for most software are designed to take away your\nfreedom to share and change it. By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it. You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n When we speak of free software, we are referring to freedom of use,\nnot price. Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights. These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou. You must make sure that they, too, receive or can get the source\ncode. If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit. And you must show them these terms so they know their rights.\n\n We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library. Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n Finally, software patents pose a constant threat to the existence of\nany free program. We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder. Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License. This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License. We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library. The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom. The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License. It also provides other free software developers Less\nof an advantage over competing non-free programs. These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries. However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard. To achieve this, non-free programs must be\nallowed to use the library. A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries. In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software. For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n The precise terms and conditions for copying, distribution and\nmodification follow. Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\". The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n\t\t GNU LESSER GENERAL PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms. A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language. (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it. For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope. The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it). Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n \n 1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n 2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n a) The modified work must itself be a software library.\n\n b) You must cause the files modified to carry prominent notices\n stating that you changed the files and the date of any change.\n\n c) You must cause the whole of the work to be licensed at no\n charge to all third parties under the terms of this License.\n\n d) If a facility in the modified Library refers to a function or a\n table of data to be supplied by an application program that uses\n the facility, other than as an argument passed when the facility\n is invoked, then you must make a good faith effort to ensure that,\n in the event an application does not supply such function or\n table, the facility still operates, and performs whatever part of\n its purpose remains meaningful.\n\n (For example, a function in a library to compute square roots has\n a purpose that is entirely well-defined independent of the\n application. Therefore, Subsection 2d requires that any\n application-supplied function or table used by this function must\n be optional: if the application does not supply it, the square\n root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole. If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works. But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n 3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library. To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License. (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.) Do not make any other change in\nthese notices.\n\f\n Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n 4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n 5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\". Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\". The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library. The\nthreshold for this to be true is not precisely defined by law.\n\n If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork. (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n 6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License. You must supply a copy of this License. If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License. Also, you must do one\nof these things:\n\n a) Accompany the work with the complete corresponding\n machine-readable source code for the Library including whatever\n changes were used in the work (which must be distributed under\n Sections 1 and 2 above); and, if the work is an executable linked\n with the Library, with the complete machine-readable \"work that\n uses the Library\", as object code and/or source code, so that the\n user can modify the Library and then relink to produce a modified\n executable containing the modified Library. (It is understood\n that the user who changes the contents of definitions files in the\n Library will not necessarily be able to recompile the application\n to use the modified definitions.)\n\n b) Use a suitable shared library mechanism for linking with the\n Library. A suitable mechanism is one that (1) uses at run time a\n copy of the library already present on the user's computer system,\n rather than copying library functions into the executable, and (2)\n will operate properly with a modified version of the library, if\n the user installs one, as long as the modified version is\n interface-compatible with the version that the work was made with.\n\n c) Accompany the work with a written offer, valid for at\n least three years, to give the same user the materials\n specified in Subsection 6a, above, for a charge no more\n than the cost of performing this distribution.\n\n d) If distribution of the work is made by offering access to copy\n from a designated place, offer equivalent access to copy the above\n specified materials from the same place.\n\n e) Verify that the user has already received a copy of these\n materials or that you have already sent this user a copy.\n\n For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it. However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system. Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n 7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n a) Accompany the combined library with a copy of the same work\n based on the Library, uncombined with any other library\n facilities. This must be distributed under the terms of the\n Sections above.\n\n b) Give prominent notice with the combined library of the fact\n that part of it is a work based on the Library, and explaining\n where to find the accompanying uncombined form of the same work.\n\n 8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License. Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License. However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n 9. You are not required to accept this License, since you have not\nsigned it. However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works. These actions are\nprohibited by law if you do not accept this License. Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n 10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions. You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n 11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all. For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices. Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n 12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded. In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n 13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation. If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n 14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission. For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this. Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n\t\t\t NO WARRANTY\n\n 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n\t\t END OF TERMS AND CONDITIONS\n\f\n How to Apply These Terms to Your New Libraries\n\n If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change. You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n To apply these terms, attach the following notices to the library. It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n \n Copyright (C) \n\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2.1 of the License, or (at your option) any later version.\n\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public\n License along with this library; if not, write to the Free Software\n Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary. Here is a sample; alter the names:\n\n Yoyodyne, Inc., hereby disclaims all copyright interest in the\n library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n , 1 April 1990\n Ty Coon, President of Vice\n\nThat's all there is to it!\n\n\n", + "License text": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL. It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n Preamble\n\n The licenses for most software are designed to take away your\nfreedom to share and change it. By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it. You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n When we speak of free software, we are referring to freedom of use,\nnot price. Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights. These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou. You must make sure that they, too, receive or can get the source\ncode. If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit. And you must show them these terms so they know their rights.\n\n We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library. Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\n Finally, software patents pose a constant threat to the existence of\nany free program. We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder. Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License. This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License. We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library. The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom. The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License. It also provides other free software developers Less\nof an advantage over competing non-free programs. These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries. However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard. To achieve this, non-free programs must be\nallowed to use the library. A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries. In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software. For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n The precise terms and conditions for copying, distribution and\nmodification follow. Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\". The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\n GNU LESSER GENERAL PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms. A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language. (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it. For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope. The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it). Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n 1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\n 2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n a) The modified work must itself be a software library.\n\n b) You must cause the files modified to carry prominent notices\n stating that you changed the files and the date of any change.\n\n c) You must cause the whole of the work to be licensed at no\n charge to all third parties under the terms of this License.\n\n d) If a facility in the modified Library refers to a function or a\n table of data to be supplied by an application program that uses\n the facility, other than as an argument passed when the facility\n is invoked, then you must make a good faith effort to ensure that,\n in the event an application does not supply such function or\n table, the facility still operates, and performs whatever part of\n its purpose remains meaningful.\n\n (For example, a function in a library to compute square roots has\n a purpose that is entirely well-defined independent of the\n application. Therefore, Subsection 2d requires that any\n application-supplied function or table used by this function must\n be optional: if the application does not supply it, the square\n root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole. If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works. But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n 3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library. To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License. (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.) Do not make any other change in\nthese notices.\n\n Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n 4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n 5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\". Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\". The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library. The\nthreshold for this to be true is not precisely defined by law.\n\n If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork. (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\n 6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License. You must supply a copy of this License. If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License. Also, you must do one\nof these things:\n\n a) Accompany the work with the complete corresponding\n machine-readable source code for the Library including whatever\n changes were used in the work (which must be distributed under\n Sections 1 and 2 above); and, if the work is an executable linked\n with the Library, with the complete machine-readable \"work that\n uses the Library\", as object code and/or source code, so that the\n user can modify the Library and then relink to produce a modified\n executable containing the modified Library. (It is understood\n that the user who changes the contents of definitions files in the\n Library will not necessarily be able to recompile the application\n to use the modified definitions.)\n\n b) Use a suitable shared library mechanism for linking with the\n Library. A suitable mechanism is one that (1) uses at run time a\n copy of the library already present on the user's computer system,\n rather than copying library functions into the executable, and (2)\n will operate properly with a modified version of the library, if\n the user installs one, as long as the modified version is\n interface-compatible with the version that the work was made with.\n\n c) Accompany the work with a written offer, valid for at\n least three years, to give the same user the materials\n specified in Subsection 6a, above, for a charge no more\n than the cost of performing this distribution.\n\n d) If distribution of the work is made by offering access to copy\n from a designated place, offer equivalent access to copy the above\n specified materials from the same place.\n\n e) Verify that the user has already received a copy of these\n materials or that you have already sent this user a copy.\n\n For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it. However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system. Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\n 7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n a) Accompany the combined library with a copy of the same work\n based on the Library, uncombined with any other library\n facilities. This must be distributed under the terms of the\n Sections above.\n\n b) Give prominent notice with the combined library of the fact\n that part of it is a work based on the Library, and explaining\n where to find the accompanying uncombined form of the same work.\n\n 8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License. Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License. However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n 9. You are not required to accept this License, since you have not\nsigned it. However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works. These actions are\nprohibited by law if you do not accept this License. Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n 10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions. You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\n 11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all. For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices. Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n 12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded. In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n 13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation. If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\n 14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission. For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this. Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n NO WARRANTY\n\n 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n END OF TERMS AND CONDITIONS\n\n How to Apply These Terms to Your New Libraries\n\n If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change. You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n To apply these terms, attach the following notices to the library. It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n \n Copyright (C) \n\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2.1 of the License, or (at your option) any later version.\n\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public\n License along with this library; if not, write to the Free Software\n Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301\n USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary. Here is a sample; alter the names:\n\n Yoyodyne, Inc., hereby disclaims all copyright interest in the\n library `Frob' (a library for tweaking knobs) written by James Random\n Hacker.\n\n , 1 April 1990\n Ty Coon, President of Vice\n\nThat's all there is to it!\n" + }, + { + "Name": "azure-mgmt-authorization", + "Version": "0.50.0", + "Summary": "Microsoft Azure Authorization Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-cognitiveservices", + "Version": "3.0.0", + "Summary": "Microsoft Azure Cognitive Services Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-telemetry", + "Version": "1.0.2", + "Summary": "Microsoft Azure CLI Telemetry Package", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-botservice", + "Version": "0.2.0", + "Summary": "Microsoft Azure Bot Service Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "wcwidth", + "Version": "0.1.7", + "Summary": "Measures number of Terminal column cells of wide-character codes", + "Home-page": "https://github.com/jquast/wcwidth", + "Author": "Jeff Quast", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2014 Jeff Quast \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-multiapi-storage", + "Version": "0.2.3", + "Summary": "Microsoft Azure Storage Client Library for Python with multi API version support.", + "Home-page": "https://github.com/Azure/azure-multiapi-storage-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "MIT License\n\nCopyright (c) 2017 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-trafficmanager", + "Version": "0.51.0", + "Summary": "Microsoft Azure Traffic Manager Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "prompt-toolkit", + "Version": "1.0.16", + "Summary": "Library for building powerful interactive command lines in Python", + "Home-page": "https://github.com/jonathanslenders/python-prompt-toolkit", + "Author": "Jonathan Slenders", + "License": "BSD 3-Clause \"New\" or \"Revised\" License", + "License repo": "Copyright (c) 2014, Jonathan Slenders\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this\n list of conditions and the following disclaimer in the documentation and/or\n other materials provided with the distribution.\n\n* Neither the name of the {organization} nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 3-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "paramiko", + "Version": "2.6.0", + "Summary": "SSH2 protocol library", + "Home-page": "https://github.com/paramiko/paramiko/", + "Author": "Jeff Forcier", + "License": "GNU Lesser General Public License v2.1", + "License repo": "\t\t GNU LESSER GENERAL PUBLIC LICENSE\n\t\t Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL. It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n\t\t\t Preamble\n\n The licenses for most software are designed to take away your\nfreedom to share and change it. By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it. You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n When we speak of free software, we are referring to freedom of use,\nnot price. Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights. These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou. You must make sure that they, too, receive or can get the source\ncode. If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit. And you must show them these terms so they know their rights.\n\n We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library. Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n Finally, software patents pose a constant threat to the existence of\nany free program. We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder. Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License. This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License. We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library. The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom. The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License. It also provides other free software developers Less\nof an advantage over competing non-free programs. These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries. However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard. To achieve this, non-free programs must be\nallowed to use the library. A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries. In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software. For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n The precise terms and conditions for copying, distribution and\nmodification follow. Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\". The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n\t\t GNU LESSER GENERAL PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms. A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language. (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it. For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope. The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it). Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n \n 1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n 2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n a) The modified work must itself be a software library.\n\n b) You must cause the files modified to carry prominent notices\n stating that you changed the files and the date of any change.\n\n c) You must cause the whole of the work to be licensed at no\n charge to all third parties under the terms of this License.\n\n d) If a facility in the modified Library refers to a function or a\n table of data to be supplied by an application program that uses\n the facility, other than as an argument passed when the facility\n is invoked, then you must make a good faith effort to ensure that,\n in the event an application does not supply such function or\n table, the facility still operates, and performs whatever part of\n its purpose remains meaningful.\n\n (For example, a function in a library to compute square roots has\n a purpose that is entirely well-defined independent of the\n application. Therefore, Subsection 2d requires that any\n application-supplied function or table used by this function must\n be optional: if the application does not supply it, the square\n root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole. If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works. But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n 3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library. To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License. (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.) Do not make any other change in\nthese notices.\n\f\n Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n 4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n 5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\". Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\". The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library. The\nthreshold for this to be true is not precisely defined by law.\n\n If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork. (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n 6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License. You must supply a copy of this License. If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License. Also, you must do one\nof these things:\n\n a) Accompany the work with the complete corresponding\n machine-readable source code for the Library including whatever\n changes were used in the work (which must be distributed under\n Sections 1 and 2 above); and, if the work is an executable linked\n with the Library, with the complete machine-readable \"work that\n uses the Library\", as object code and/or source code, so that the\n user can modify the Library and then relink to produce a modified\n executable containing the modified Library. (It is understood\n that the user who changes the contents of definitions files in the\n Library will not necessarily be able to recompile the application\n to use the modified definitions.)\n\n b) Use a suitable shared library mechanism for linking with the\n Library. A suitable mechanism is one that (1) uses at run time a\n copy of the library already present on the user's computer system,\n rather than copying library functions into the executable, and (2)\n will operate properly with a modified version of the library, if\n the user installs one, as long as the modified version is\n interface-compatible with the version that the work was made with.\n\n c) Accompany the work with a written offer, valid for at\n least three years, to give the same user the materials\n specified in Subsection 6a, above, for a charge no more\n than the cost of performing this distribution.\n\n d) If distribution of the work is made by offering access to copy\n from a designated place, offer equivalent access to copy the above\n specified materials from the same place.\n\n e) Verify that the user has already received a copy of these\n materials or that you have already sent this user a copy.\n\n For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it. However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system. Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n 7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n a) Accompany the combined library with a copy of the same work\n based on the Library, uncombined with any other library\n facilities. This must be distributed under the terms of the\n Sections above.\n\n b) Give prominent notice with the combined library of the fact\n that part of it is a work based on the Library, and explaining\n where to find the accompanying uncombined form of the same work.\n\n 8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License. Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License. However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n 9. You are not required to accept this License, since you have not\nsigned it. However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works. These actions are\nprohibited by law if you do not accept this License. Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n 10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions. You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n 11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all. For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices. Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n 12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded. In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n 13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation. If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n 14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission. For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this. Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n\t\t\t NO WARRANTY\n\n 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n\t\t END OF TERMS AND CONDITIONS\n\f\n How to Apply These Terms to Your New Libraries\n\n If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change. You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n To apply these terms, attach the following notices to the library. It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n \n Copyright (C) \n\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2.1 of the License, or (at your option) any later version.\n\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public\n License along with this library; if not, write to the Free Software\n Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary. Here is a sample; alter the names:\n\n Yoyodyne, Inc., hereby disclaims all copyright interest in the\n library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n , 1 April 1990\n Ty Coon, President of Vice\n\nThat's all there is to it!\n\n\n", + "License text": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL. It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n Preamble\n\n The licenses for most software are designed to take away your\nfreedom to share and change it. By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it. You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n When we speak of free software, we are referring to freedom of use,\nnot price. Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights. These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou. You must make sure that they, too, receive or can get the source\ncode. If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit. And you must show them these terms so they know their rights.\n\n We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library. Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\n Finally, software patents pose a constant threat to the existence of\nany free program. We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder. Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License. This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License. We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library. The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom. The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License. It also provides other free software developers Less\nof an advantage over competing non-free programs. These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries. However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard. To achieve this, non-free programs must be\nallowed to use the library. A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries. In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software. For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n The precise terms and conditions for copying, distribution and\nmodification follow. Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\". The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\n GNU LESSER GENERAL PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms. A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language. (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it. For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope. The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it). Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n 1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\n 2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n a) The modified work must itself be a software library.\n\n b) You must cause the files modified to carry prominent notices\n stating that you changed the files and the date of any change.\n\n c) You must cause the whole of the work to be licensed at no\n charge to all third parties under the terms of this License.\n\n d) If a facility in the modified Library refers to a function or a\n table of data to be supplied by an application program that uses\n the facility, other than as an argument passed when the facility\n is invoked, then you must make a good faith effort to ensure that,\n in the event an application does not supply such function or\n table, the facility still operates, and performs whatever part of\n its purpose remains meaningful.\n\n (For example, a function in a library to compute square roots has\n a purpose that is entirely well-defined independent of the\n application. Therefore, Subsection 2d requires that any\n application-supplied function or table used by this function must\n be optional: if the application does not supply it, the square\n root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole. If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works. But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n 3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library. To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License. (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.) Do not make any other change in\nthese notices.\n\n Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n 4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n 5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\". Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\". The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library. The\nthreshold for this to be true is not precisely defined by law.\n\n If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork. (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\n 6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License. You must supply a copy of this License. If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License. Also, you must do one\nof these things:\n\n a) Accompany the work with the complete corresponding\n machine-readable source code for the Library including whatever\n changes were used in the work (which must be distributed under\n Sections 1 and 2 above); and, if the work is an executable linked\n with the Library, with the complete machine-readable \"work that\n uses the Library\", as object code and/or source code, so that the\n user can modify the Library and then relink to produce a modified\n executable containing the modified Library. (It is understood\n that the user who changes the contents of definitions files in the\n Library will not necessarily be able to recompile the application\n to use the modified definitions.)\n\n b) Use a suitable shared library mechanism for linking with the\n Library. A suitable mechanism is one that (1) uses at run time a\n copy of the library already present on the user's computer system,\n rather than copying library functions into the executable, and (2)\n will operate properly with a modified version of the library, if\n the user installs one, as long as the modified version is\n interface-compatible with the version that the work was made with.\n\n c) Accompany the work with a written offer, valid for at\n least three years, to give the same user the materials\n specified in Subsection 6a, above, for a charge no more\n than the cost of performing this distribution.\n\n d) If distribution of the work is made by offering access to copy\n from a designated place, offer equivalent access to copy the above\n specified materials from the same place.\n\n e) Verify that the user has already received a copy of these\n materials or that you have already sent this user a copy.\n\n For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it. However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system. Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\n 7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n a) Accompany the combined library with a copy of the same work\n based on the Library, uncombined with any other library\n facilities. This must be distributed under the terms of the\n Sections above.\n\n b) Give prominent notice with the combined library of the fact\n that part of it is a work based on the Library, and explaining\n where to find the accompanying uncombined form of the same work.\n\n 8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License. Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License. However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n 9. You are not required to accept this License, since you have not\nsigned it. However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works. These actions are\nprohibited by law if you do not accept this License. Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n 10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions. You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\n 11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all. For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices. Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n 12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded. In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n 13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation. If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\n 14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission. For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this. Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n NO WARRANTY\n\n 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n END OF TERMS AND CONDITIONS\n\n How to Apply These Terms to Your New Libraries\n\n If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change. You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n To apply these terms, attach the following notices to the library. It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n \n Copyright (C) \n\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2.1 of the License, or (at your option) any later version.\n\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public\n License along with this library; if not, write to the Free Software\n Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301\n USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary. Here is a sample; alter the names:\n\n Yoyodyne, Inc., hereby disclaims all copyright interest in the\n library `Frob' (a library for tweaking knobs) written by James Random\n Hacker.\n\n , 1 April 1990\n Ty Coon, President of Vice\n\nThat's all there is to it!\n" + }, + { + "Name": "azure-mgmt-servicebus", + "Version": "0.6.0", + "Summary": "Microsoft Azure Service Bus Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-sqlvm", + "Version": "0.2.0", + "Summary": "Microsoft Azure Command-Line Tools SQL virtual machine Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-rdbms", + "Version": "0.3.12", + "Summary": "Microsoft Azure Command-Line Tools MySQL and PostgreSQL Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "sshtunnel", + "Version": "0.1.5", + "Summary": "Pure python SSH tunnels", + "Home-page": "https://github.com/pahaz/sshtunnel", + "Author": "Pahaz Blinov", + "License": "MIT License", + "License repo": "Copyright (c) 2014-2019 Pahaz Blinov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-billing", + "Version": "0.2.2", + "Summary": "Microsoft Azure Command-Line Tools Billing Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-policyinsights", + "Version": "0.1.4", + "Summary": "Microsoft Azure Command-Line Tools Policy Insights Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "Pygments", + "Version": "2.4.2", + "Summary": "Pygments is a syntax highlighting package written in Python.", + "Home-page": "http://pygments.org/", + "Author": "Georg Brandl", + "License": "BSD License" + }, + { + "Name": "botocore", + "Version": "1.12.225", + "Summary": "Low-level, data-driven core of boto 3.", + "Home-page": "https://github.com/boto/botocore", + "Author": "Amazon Web Services", + "License": "Apache License 2.0", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "azure-cli-role", + "Version": "2.6.4", + "Summary": "Microsoft Azure Command-Line Tools Role Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-servicefabric", + "Version": "0.2.0", + "Summary": "Microsoft Azure Service Fabric Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "invoke", + "Version": "1.3.0", + "Summary": "Pythonic task execution", + "Home-page": "http://docs.pyinvoke.org", + "Author": "Jeff Forcier", + "License": "BSD" + }, + { + "Name": "azure-cli-storage", + "Version": "2.4.3", + "Summary": "Microsoft Azure Command-Line Tools Storage Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "oauthlib", + "Version": "3.1.0", + "Summary": "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic", + "Home-page": "https://github.com/oauthlib/oauthlib", + "Author": "The OAuthlib Community", + "License": "BSD 3-Clause \"New\" or \"Revised\" License", + "License repo": "Copyright (c) 2019 The OAuthlib Community\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n\n 3. Neither the name of this project nor the names of its contributors may\n be used to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 3-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "azure-cli-keyvault", + "Version": "2.2.16", + "Summary": "Microsoft Azure Command-Line Tools Keyvault Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-functions-devops-build", + "Version": "0.0.22", + "Summary": "Python package for integrating Azure Functions with Azure DevOps. Specifically made for the Azure CLI", + "Home-page": "https://github.com/Azure/azure-functions-devops-build", + "Author": "Oliver Dolk, Hanzhang Zeng", + "License": "MIT License", + "License repo": " MIT License\n\n Copyright (c) Microsoft Corporation. All rights reserved.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-redis", + "Version": "6.0.0", + "Summary": "Microsoft Azure Redis Cache Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "tabulate", + "Version": "0.8.3", + "Summary": "Pretty-print tabular data", + "Home-page": "https://bitbucket.org/astanin/python-tabulate", + "Author": "Sergey Astanin", + "License": "MIT" + }, + { + "Name": "scp", + "Version": "0.13.2", + "Summary": "scp module for paramiko", + "Home-page": "https://github.com/jbardin/scp.py", + "Author": "James Bardin", + "License": "Other", + "License repo": "# This library is free software; you can redistribute it and/or\n# modify it under the terms of the GNU Lesser General Public\n# License as published by the Free Software Foundation; either\n# version 2.1 of the License, or (at your option) any later version.\n#\n# This library is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n# Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public\n# License along with this library; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\n" + }, + { + "Name": "azure-mgmt-containerinstance", + "Version": "1.4.0", + "Summary": "Microsoft Azure Container Instance Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": ": Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "pyOpenSSL", + "Version": "19.0.0", + "Summary": "Python wrapper module around the OpenSSL library", + "Home-page": "https://pyopenssl.org/", + "Author": "The pyOpenSSL developers", + "License": "Apache License, Version 2.0" + }, + { + "Name": "colorama", + "Version": "0.4.1", + "Summary": "Cross-platform colored terminal text.", + "Home-page": "https://github.com/tartley/colorama", + "Author": "Jonathan Hartley", + "License": "BSD 3-Clause \"New\" or \"Revised\" License", + "License repo": "Copyright (c) 2010 Jonathan Hartley\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holders, nor those of its contributors\n may be used to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 3-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "azure-mgmt-search", + "Version": "2.0.0", + "Summary": "Microsoft Azure Search Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-datalake-nspkg", + "Version": "3.0.1", + "Summary": "Microsoft Azure Data Lake Management Namespace Package [Internal]", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-relay", + "Version": "0.1.0", + "Summary": "Microsoft Azure Relay Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-cdn", + "Version": "0.2.4", + "Summary": "Microsoft Azure Command-Line Tools Content Delivery Network (CDN) Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "docutils", + "Version": "0.15.2", + "Summary": "Docutils -- Python Documentation Utilities", + "Home-page": "http://docutils.sourceforge.net/", + "Author": "David Goodger", + "License": "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)" + }, + { + "Name": "azure-cli-maps", + "Version": "0.3.5", + "Summary": "Microsoft Azure Command-Line Tools Maps Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "PyJWT", + "Version": "1.7.1", + "Summary": "JSON Web Token implementation in Python", + "Home-page": "http://github.com/jpadilla/pyjwt", + "Author": "Jose Padilla", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2015 Jos\u00e9 Padilla\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-containerregistry", + "Version": "2.8.0", + "Summary": "Microsoft Azure Container Registry Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-managementgroups", + "Version": "0.1.0", + "Summary": "Microsoft Azure Management Groups Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-web", + "Version": "0.42.0", + "Summary": "Microsoft Azure Web Apps Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "PyNaCl", + "Version": "1.3.0", + "Summary": "Python binding to the Networking and Cryptography (NaCl) library", + "Home-page": "https://github.com/pyca/pynacl/", + "Author": "The PyNaCl developers", + "License": "Apache License 2.0", + "License repo": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "cffi", + "Version": "1.12.3", + "Summary": "Foreign Function Interface for Python calling C code.", + "Home-page": "http://cffi.readthedocs.org", + "Author": "Armin Rigo, Maciej Fijalkowski", + "License": "MIT" + }, + { + "Name": "boto3", + "Version": "1.9.225", + "Summary": "The AWS SDK for Python", + "Home-page": "https://github.com/boto/boto3", + "Author": "Amazon Web Services", + "License": "Apache License 2.0", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "azure-mgmt-consumption", + "Version": "2.0.0", + "Summary": "Microsoft Azure Consumption Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-datalake-store", + "Version": "0.5.0", + "Summary": "Microsoft Azure Data Lake Store Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-dms", + "Version": "0.1.4", + "Summary": "Microsoft Azure Command-Line Tools for the Data Migration Service (DMS) Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-servicebus", + "Version": "0.3.6", + "Summary": "Microsoft Azure Command-Line Tools Service Bus Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-network", + "Version": "2.5.2", + "Summary": "Microsoft Azure Command-Line Tools Network Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-signalr", + "Version": "0.1.1", + "Summary": "Microsoft Azure SignalR Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-acs", + "Version": "2.4.4", + "Summary": "Microsoft Azure Command-Line Tools ACS Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "vsts-cd-manager", + "Version": "1.0.2", + "Summary": "Python wrapper around some of the VSTS APIs", + "Home-page": "https://github.com/microsoft/vsts-cd-manager", + "Author": "UNKNOWN", + "License": "MIT License", + "License repo": " MIT License\r\n\r\n Copyright (c) Microsoft Corporation. All rights reserved.\r\n\r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n\r\n The above copyright notice and this permission notice shall be included in all\r\n copies or substantial portions of the Software.\r\n\r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n SOFTWARE\r\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-sql", + "Version": "2.2.5", + "Summary": "Microsoft Azure Command-Line Tools SQL Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-recoveryservicesbackup", + "Version": "0.1.2", + "Summary": "Microsoft Azure Recovery Services Backup Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-marketplaceordering", + "Version": "0.1.0", + "Summary": "Microsoft Azure Market Place Ordering Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-cognitiveservices", + "Version": "0.2.6", + "Summary": "Microsoft Azure Command-Line Tools Cognitive Services Command Module", + "Home-page": "https://github.com/azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-hdinsight", + "Version": "0.3.5", + "Summary": "Microsoft Azure Command-Line Tools HDInsight Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-storage-blob", + "Version": "1.3.1", + "Summary": "Microsoft Azure Storage Blob Client Library for Python", + "Home-page": "https://github.com/Azure/azure-storage-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2017 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-advisor", + "Version": "2.0.1", + "Summary": "Microsoft Azure Advisor Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "msrest", + "Version": "0.6.10", + "Summary": "AutoRest swagger generator Python client runtime.", + "Home-page": "https://github.com/Azure/msrest-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Azure\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-batch", + "Version": "6.0.0", + "Summary": "Microsoft Azure Batch Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-resource", + "Version": "2.1.16", + "Summary": "Microsoft Azure Command-Line Tools Resource Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "psutil", + "Version": "5.6.3", + "Summary": "Cross-platform lib for process and system monitoring in Python.", + "Home-page": "https://github.com/giampaolo/psutil", + "Author": "Giampaolo Rodola", + "License": "BSD 3-Clause \"New\" or \"Revised\" License", + "License repo": "BSD 3-Clause License\n\nCopyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n * Neither the name of the psutil authors nor the names of its contributors\n may be used to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "License text": "BSD 3-Clause License\n\nCopyright (c) [year], [fullname]\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "Name": "azure-cli-extension", + "Version": "0.2.5", + "Summary": "Microsoft Azure Command-Line Tools Extension Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-lab", + "Version": "0.1.8", + "Summary": "Microsoft Azure Command-Line Tools DevTestLabs Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "bcrypt", + "Version": "3.1.7", + "Summary": "Modern password hashing for your software and your servers", + "Home-page": "https://github.com/pyca/bcrypt/", + "Author": "The Python Cryptographic Authority developers", + "License": "Apache License 2.0", + "License repo": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "s3transfer", + "Version": "0.2.1", + "Summary": "An Amazon S3 Transfer Manager", + "Home-page": "https://github.com/boto/s3transfer", + "Author": "Amazon Web Services", + "License": "Apache License 2.0", + "License repo": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n", + "License text": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "Name": "azure-graphrbac", + "Version": "0.60.0", + "Summary": "Microsoft Azure Graph RBAC Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "attrs", + "Version": "19.1.0", + "Summary": "Classes Without Boilerplate", + "Home-page": "https://www.attrs.org/", + "Author": "Hynek Schlawack", + "License": "MIT" + }, + { + "Name": "azure-cli-monitor", + "Version": "0.2.15", + "Summary": "Microsoft Azure Command-Line Tools Monitor Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-billing", + "Version": "0.2.0", + "Summary": "Microsoft Azure Billing Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-botservice", + "Version": "0.2.2", + "Summary": "Microsoft Azure Command-Line Tools Bot Services Command Module", + "Home-page": "https://github.com/azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-signalr", + "Version": "1.0.1", + "Summary": "Microsoft Azure Command-Line Tools SignalR Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-batchai", + "Version": "2.0.0", + "Summary": "Microsoft Azure Batch AI Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "mock", + "Version": "3.0.5", + "Summary": "Rolling backport of unittest.mock for all Pythons", + "Home-page": "http://mock.readthedocs.org/en/latest/", + "Author": "Testing Cabal", + "License": "OSI Approved :: BSD License" + }, + { + "Name": "applicationinsights", + "Version": "0.11.7", + "Summary": "This project extends the Application Insights API surface to support Python.", + "Home-page": "https://github.com/Microsoft/ApplicationInsights-Python", + "Author": "Microsoft", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2018 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "certifi", + "Version": "2019.6.16", + "Summary": "Python package for providing Mozilla's CA Bundle.", + "Home-page": "https://certifi.io/", + "Author": "Kenneth Reitz", + "License": "MPL-2.0" + }, + { + "Name": "portalocker", + "Version": "1.2.1", + "Summary": "Wraps the portalocker recipe for easy usage", + "Home-page": "https://github.com/WoLpH/portalocker", + "Author": "Rick van Hattem", + "License": "Other", + "License repo": "PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2\n--------------------------------------------\n\n1. This LICENSE AGREEMENT is between the Python Software Foundation\n(\"PSF\"), and the Individual or Organization (\"Licensee\") accessing and\notherwise using this software (\"Python\") in source or binary form and\nits associated documentation.\n\n2. Subject to the terms and conditions of this License Agreement, PSF hereby\ngrants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,\nanalyze, test, perform and/or display publicly, prepare derivative works,\ndistribute, and otherwise use Python alone or in any derivative version,\nprovided, however, that PSF's License Agreement and PSF's notice of copyright,\ni.e., \"Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010\nPython Software Foundation; All Rights Reserved\" are retained in Python alone or\nin any derivative version prepared by Licensee.\n\n3. In the event Licensee prepares a derivative work that is based on\nor incorporates Python or any part thereof, and wants to make\nthe derivative work available to others as provided herein, then\nLicensee hereby agrees to include in any such work a brief summary of\nthe changes made to Python.\n\n4. PSF is making Python available to Licensee on an \"AS IS\"\nbasis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR\nIMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND\nDISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS\nFOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT\nINFRINGE ANY THIRD PARTY RIGHTS.\n\n5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON\nFOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS\nA RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,\nOR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.\n\n6. This License Agreement will automatically terminate upon a material\nbreach of its terms and conditions.\n\n7. Nothing in this License Agreement shall be deemed to create any\nrelationship of agency, partnership, or joint venture between PSF and\nLicensee. This License Agreement does not grant permission to use PSF\ntrademarks or trade name in a trademark sense to endorse or promote\nproducts or services of Licensee, or any third party.\n\n8. By copying, installing or otherwise using Python, Licensee\nagrees to be bound by the terms and conditions of this License\nAgreement.\n\n" + }, + { + "Name": "azure-cli-nspkg", + "Version": "3.0.4", + "Summary": "Microsoft Azure CLI Namespace Package", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-batch", + "Version": "4.0.3", + "Summary": "Microsoft Azure Command-Line Tools Batch Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-iotcentral", + "Version": "1.0.0", + "Summary": "Microsoft Azure IoTCentral Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-rdbms", + "Version": "1.8.0", + "Summary": "Microsoft Azure RDBMS Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-keyvault", + "Version": "1.1.0", + "Summary": "Microsoft Azure Key Vault Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-network", + "Version": "3.0.0", + "Summary": "Microsoft Azure Network Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-batch", + "Version": "6.0.0", + "Summary": "Microsoft Azure Batch Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cosmos", + "Version": "3.1.1", + "Summary": "Azure Cosmos Python SDK", + "Home-page": "https://github.com/Azure/azure-documentdb-python", + "Author": "Microsoft", + "License": "MIT License", + "License repo": "The MIT License (MIT)\nCopyright (c) 2014 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-relay", + "Version": "0.1.5", + "Summary": "Microsoft Azure Command-Line Tools Relay Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-core", + "Version": "2.0.67", + "Summary": "Microsoft Azure Command-Line Tools Core Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "adal", + "Version": "1.2.2", + "Summary": "The ADAL for Python library makes it easy for python application to authenticate to Azure Active Directory (AAD) in order to access AAD protected web resources.", + "Home-page": "https://github.com/AzureAD/azure-activedirectory-library-for-python", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "The MIT License (MIT)\n\nCopyright (c) Microsoft Corporation. \nAll rights reserved.\n\nThis code is licensed under the MIT License.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files(the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and / or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions :\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE." + }, + { + "Name": "Jinja2", + "Version": "2.10.1", + "Summary": "A small but fast and easy to use stand-alone template engine written in pure python.", + "Home-page": "http://jinja.pocoo.org/", + "Author": "Armin Ronacher", + "License": "BSD" + }, + { + "Name": "azure-cli-iot", + "Version": "0.3.11", + "Summary": "Microsoft Azure Command-Line Tools IoT Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-compute", + "Version": "5.0.0", + "Summary": "Microsoft Azure Compute Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-recoveryservices", + "Version": "0.1.1", + "Summary": "Microsoft Azure Recovery Services Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-iothub", + "Version": "0.8.2", + "Summary": "Microsoft Azure IoTHub Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-security", + "Version": "0.1.2", + "Summary": "Microsoft Azure Command-Line Tools Azure Security Center", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-datamigration", + "Version": "0.1.0", + "Summary": "Microsoft Azure Data Migration Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-maps", + "Version": "0.1.0", + "Summary": "Microsoft Azure Maps Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-containerservice", + "Version": "5.2.0", + "Summary": "Microsoft Azure Container Service Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "six", + "Version": "1.12.0", + "Summary": "Python 2 and 3 compatibility utilities", + "Home-page": "https://github.com/benjaminp/six", + "Author": "Benjamin Peterson", + "License": "MIT License", + "License repo": "Copyright (c) 2010-2019 Benjamin Peterson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-dls", + "Version": "0.1.10", + "Summary": "Microsoft Azure Command-Line Tools Data Lake Store Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-container", + "Version": "0.3.18", + "Summary": "Microsoft Azure Command-Line Tools container Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-reservations", + "Version": "0.3.1", + "Summary": "Microsoft Azure Reservations Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-backup", + "Version": "1.2.5", + "Summary": "Microsoft Azure Command-Line Tools Recovery Services Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-media", + "Version": "1.1.1", + "Summary": "Microsoft Azure Media Services Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-servicefabric", + "Version": "0.1.20", + "Summary": "Microsoft Azure Service Fabric Command-Line Tools", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-deploymentmanager", + "Version": "0.1.0", + "Summary": "Microsoft Azure Deployment Manager Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-policyinsights", + "Version": "0.3.1", + "Summary": "Microsoft Azure Policy Insights Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-profile", + "Version": "2.1.5", + "Summary": "Microsoft Azure Command-Line Tools Profile Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "pytz", + "Version": "2019.2", + "Summary": "World timezone definitions, modern and historical", + "Home-page": "http://pythonhosted.org/pytz", + "Author": "Stuart Bishop", + "License": "MIT" + }, + { + "Name": "pyrsistent", + "Version": "0.15.4", + "Summary": "Persistent/Functional/Immutable data structures", + "Home-page": "http://github.com/tobgu/pyrsistent/", + "Author": "Tobias Gustafsson", + "License": "MIT License", + "License repo": "Copyright (c) 2019 Tobias Gustafsson\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "msrestazure", + "Version": "0.6.1", + "Summary": "AutoRest swagger generator Python client runtime. Azure-specific module.", + "Home-page": "https://github.com/Azure/msrestazure-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Azure\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-kusto", + "Version": "0.3.0", + "Summary": "Microsoft Azure Kusto Management Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-iotcentral", + "Version": "0.1.7", + "Summary": "Microsoft Azure Command-Line Tools IoT Central Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "ansible", + "Version": "2.8.4", + "Summary": "Radically simple IT automation", + "Home-page": "https://ansible.com/", + "Author": "Ansible, Inc.", + "License": "GPLv3+" + }, + { + "Name": "azure-cli-natgateway", + "Version": "0.1.1", + "Summary": "Microsoft Azure Command-Line Tools NatGateway Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-cli-cloud", + "Version": "2.1.1", + "Summary": "Microsoft Azure Command-Line Tools Cloud Command Module", + "Home-page": "https://github.com/Azure/azure-cli", + "Author": "Microsoft Corporation", + "License": "Other", + "License repo": "MIT License\n\nCopyright (c) 2016 Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-nspkg", + "Version": "3.0.2", + "Summary": "Microsoft Azure Namespace Package [Internal]", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + }, + { + "Name": "azure-mgmt-monitor", + "Version": "0.5.2", + "Summary": "Microsoft Azure Monitor Client Library for Python", + "Home-page": "https://github.com/Azure/azure-sdk-for-python", + "Author": "Microsoft Corporation", + "License": "MIT License", + "License repo": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", "License text": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" } ] \ No newline at end of file diff --git a/core/src/epicli/cli/version.py b/core/src/epicli/cli/version.py index b7d829d052..698a3f5800 100644 --- a/core/src/epicli/cli/version.py +++ b/core/src/epicli/cli/version.py @@ -1 +1 @@ -VERSION = '0.3.0' \ No newline at end of file +VERSION = '0.4.0' \ No newline at end of file diff --git a/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml index e64f0eb838..d301058a7d 100644 --- a/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml @@ -1,5 +1,5 @@ kind: epiphany-cluster -version: 0.3.0 +version: 0.4.0 title: "Epiphany cluster Config" provider: any name: "default" diff --git a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml index 53add74846..28b3526024 100644 --- a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml @@ -1,5 +1,5 @@ kind: epiphany-cluster -version: 0.3.0 +version: 0.4.0 title: "Epiphany cluster Config" provider: aws name: "default" diff --git a/core/src/epicli/data/aws/defaults/infrastructure/default-security-group.yml b/core/src/epicli/data/aws/defaults/infrastructure/default-security-group.yml index 91826229d9..d9d2e1281e 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/default-security-group.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/default-security-group.yml @@ -1,5 +1,5 @@ kind: infrastructure/default-security-group -version: 0.3.0 +version: 0.4.0 title: "Default Security Group Config" provider: aws name: default-security-group diff --git a/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml b/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml index 73053e90ae..e9b6189c2d 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/efs-storage.yml @@ -1,5 +1,5 @@ kind: infrastructure/efs-storage -version: 0.3.0 +version: 0.4.0 title: "Elastic File System Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/internet-gateway.yml b/core/src/epicli/data/aws/defaults/infrastructure/internet-gateway.yml index 62670f3a75..f7f07752bc 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/internet-gateway.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/internet-gateway.yml @@ -1,5 +1,5 @@ kind: infrastructure/internet-gateway -version: 0.3.0 +version: 0.4.0 title: "Internet Gateway Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/launch-configuration.yml b/core/src/epicli/data/aws/defaults/infrastructure/launch-configuration.yml index d6a62a7413..983334c25c 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/launch-configuration.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/launch-configuration.yml @@ -1,5 +1,5 @@ kind: infrastructure/launch-configuration -version: 0.3.0 +version: 0.4.0 title: "Launch configuration" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/public-key.yml b/core/src/epicli/data/aws/defaults/infrastructure/public-key.yml index 04ac391635..ab420ee069 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/public-key.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/public-key.yml @@ -1,5 +1,5 @@ kind: infrastructure/public-key -version: 0.3.0 +version: 0.4.0 title: "Public Key" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/resource-group.yml b/core/src/epicli/data/aws/defaults/infrastructure/resource-group.yml index 0a5022cc7f..92fa7b24f5 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/resource-group.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/resource-group.yml @@ -1,5 +1,5 @@ kind: infrastructure/resource-group -version: 0.3.0 +version: 0.4.0 title: "Resource Group" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/route-table-association.yml b/core/src/epicli/data/aws/defaults/infrastructure/route-table-association.yml index b32e4ed5e5..8595e68034 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/route-table-association.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/route-table-association.yml @@ -1,5 +1,5 @@ kind: infrastructure/route-table-association -version: 0.3.0 +version: 0.4.0 title: Route Table Association Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/route-table.yml b/core/src/epicli/data/aws/defaults/infrastructure/route-table.yml index 66ec76300d..46deb87ccf 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/route-table.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/route-table.yml @@ -1,5 +1,5 @@ kind: infrastructure/route-table -version: 0.3.0 +version: 0.4.0 title: "Route Table Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/security-group-rule.yml b/core/src/epicli/data/aws/defaults/infrastructure/security-group-rule.yml index 99a73f254b..d37a024ff5 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/security-group-rule.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/security-group-rule.yml @@ -1,5 +1,5 @@ kind: infrastructure/security-group-rule -version: 0.3.0 +version: 0.4.0 title: "Default Group Rule" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/security-group.yml b/core/src/epicli/data/aws/defaults/infrastructure/security-group.yml index 1de2eb4bb5..71f0f7eabb 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/security-group.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/security-group.yml @@ -1,5 +1,5 @@ kind: infrastructure/security-group -version: 0.3.0 +version: 0.4.0 title: "Security Group Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/subnet.yml b/core/src/epicli/data/aws/defaults/infrastructure/subnet.yml index 60465f1646..cd9dd7e7b7 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/subnet.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/subnet.yml @@ -1,5 +1,5 @@ kind: infrastructure/subnet -version: 0.3.0 +version: 0.4.0 title: "Subnet Config" provider: aws name: default diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 8593015543..3f88d7aca7 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -1,5 +1,5 @@ kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: default @@ -13,7 +13,7 @@ specification: authorized_to_efs: false mount_efs: false tags: - - version: 0.3.0 + - version: 0.4.0 size: t2.micro os_full_name: "ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-20190212.1" os_type: linux @@ -64,13 +64,13 @@ specification: --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: default-size-t3 specification: tags: - - version: 0.3.0 + - version: 0.4.0 size: t3.micro os_type: linux security: @@ -97,13 +97,13 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: rabbitmq-machine specification: tags: - - version: 0.3.0 + - version: 0.4.0 size: t3.micro os_type: linux security: @@ -150,13 +150,13 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: load-balancer-machine specification: tags: - - version: 0.3.0 + - version: 0.4.0 size: t3.micro os_type: linux security: @@ -203,7 +203,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: kubernetes-master-machine @@ -293,7 +293,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: kubernetes-node-machine @@ -371,7 +371,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: kafka-machine @@ -497,7 +497,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: monitoring-machine @@ -557,7 +557,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: postgresql-machine @@ -621,7 +621,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: aws name: logging-machine diff --git a/core/src/epicli/data/aws/defaults/infrastructure/vpc.yml b/core/src/epicli/data/aws/defaults/infrastructure/vpc.yml index 2938c14af9..b8ab68df82 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/vpc.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/vpc.yml @@ -1,5 +1,5 @@ kind: infrastructure/vpc -version: 0.3.0 +version: 0.4.0 title: "VPC Config" provider: aws name: default diff --git a/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml index 265392edf2..13b5dcc993 100644 --- a/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml @@ -1,5 +1,5 @@ kind: epiphany-cluster -version: 0.3.0 +version: 0.4.0 title: "Epiphany cluster Config" provider: azure name: "default" diff --git a/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml b/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml index 251d0b9ee4..bb9972c982 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/network-interface.yml @@ -1,5 +1,5 @@ kind: infrastructure/network-interface -version: 0.3.0 +version: 0.4.0 title: "Network Interface Config" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml b/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml index 8bbca2698c..7093dd1716 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/network-security-group.yml @@ -1,5 +1,5 @@ kind: infrastructure/network-security-group -version: 0.3.0 +version: 0.4.0 title: "Security Group Config" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml b/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml index 0fde9dd74c..476131eff8 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/public-ip.yml @@ -1,5 +1,5 @@ kind: infrastructure/public-ip -version: 0.3.0 +version: 0.4.0 title: "Public IP Config" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml b/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml index 1835a6fb3e..30e7e80ef4 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/resource-group.yml @@ -1,5 +1,5 @@ kind: infrastructure/resource-group -version: 0.3.0 +version: 0.4.0 title: "Resource Group" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml b/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml index ab113fede2..d949997924 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/subnet-network-security-group-association.yml @@ -1,5 +1,5 @@ kind: infrastructure/subnet-network-security-group-association -version: 0.3.0 +version: 0.4.0 title: "Subnet Network Security Group Association" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml index f2ace2cf73..d6a680316d 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/subnet.yml @@ -1,5 +1,5 @@ kind: infrastructure/subnet -version: 0.3.0 +version: 0.4.0 title: "Subnet Config" provider: azure name: default diff --git a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml index d19dfff26b..38af52c9e0 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml @@ -1,5 +1,5 @@ kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: default @@ -65,7 +65,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: kubernetes-master-machine @@ -153,7 +153,7 @@ specification: # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: kubernetes-node-machine @@ -229,7 +229,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: kafka-machine @@ -355,7 +355,7 @@ specification: # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: rabbit-machine @@ -405,7 +405,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: monitoring-machine @@ -465,7 +465,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: postgresql-machine @@ -529,7 +529,7 @@ specification: # destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: logging-machine @@ -599,7 +599,7 @@ specification: destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: azure name: load-balancer-machine diff --git a/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml index edefde5dc1..b524337231 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/vnet.yml @@ -1,5 +1,5 @@ kind: infrastructure/vnet -version: 0.3.0 +version: 0.4.0 title: "VNET Config" provider: azure name: default diff --git a/core/src/epicli/data/common/defaults/configuration/applications.yml b/core/src/epicli/data/common/defaults/configuration/applications.yml index ff6162818d..5ee34f7259 100644 --- a/core/src/epicli/data/common/defaults/configuration/applications.yml +++ b/core/src/epicli/data/common/defaults/configuration/applications.yml @@ -1,5 +1,5 @@ kind: configuration/applications -version: 0.3.0 +version: 0.4.0 title: "Kubernetes Applications Config" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/elasticsearch-curator.yml b/core/src/epicli/data/common/defaults/configuration/elasticsearch-curator.yml index c31f9e68a3..c7061d5c80 100644 --- a/core/src/epicli/data/common/defaults/configuration/elasticsearch-curator.yml +++ b/core/src/epicli/data/common/defaults/configuration/elasticsearch-curator.yml @@ -1,5 +1,5 @@ kind: configuration/elasticsearch-curator -version: 0.3.0 +version: 0.4.0 title: "ElasticSearch curator" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/elasticsearch.yml b/core/src/epicli/data/common/defaults/configuration/elasticsearch.yml index 9fbdd405eb..50bfd0fa91 100644 --- a/core/src/epicli/data/common/defaults/configuration/elasticsearch.yml +++ b/core/src/epicli/data/common/defaults/configuration/elasticsearch.yml @@ -1,5 +1,5 @@ kind: configuration/elasticsearch -version: 0.3.0 +version: 0.4.0 title: "ElasticSearch Config" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml index 9c79a0152e..be55a11932 100644 --- a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml +++ b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml @@ -1,5 +1,5 @@ kind: configuration/feature-mapping -version: 0.3.0 +version: 0.4.0 title: "Feature mapping to roles" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/filebeat.yml b/core/src/epicli/data/common/defaults/configuration/filebeat.yml index ca45864e5b..ba8712a03b 100644 --- a/core/src/epicli/data/common/defaults/configuration/filebeat.yml +++ b/core/src/epicli/data/common/defaults/configuration/filebeat.yml @@ -1,5 +1,5 @@ kind: configuration/filebeat -version: 0.3.0 +version: 0.4.0 title: "Filebeat" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/grafana.yml b/core/src/epicli/data/common/defaults/configuration/grafana.yml index ee77ec0a93..ed50556f63 100644 --- a/core/src/epicli/data/common/defaults/configuration/grafana.yml +++ b/core/src/epicli/data/common/defaults/configuration/grafana.yml @@ -1,5 +1,5 @@ kind: configuration/grafana -version: 0.3.0 +version: 0.4.0 title: "Grafana" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/haproxy-exporter.yml b/core/src/epicli/data/common/defaults/configuration/haproxy-exporter.yml index e9b0e6df18..a18bacf46d 100644 --- a/core/src/epicli/data/common/defaults/configuration/haproxy-exporter.yml +++ b/core/src/epicli/data/common/defaults/configuration/haproxy-exporter.yml @@ -1,5 +1,5 @@ kind: configuration/haproxy-exporter -version: 0.3.0 +version: 0.4.0 title: "HAProxy exporter" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/haproxy.yml b/core/src/epicli/data/common/defaults/configuration/haproxy.yml index 5a0ec93aad..8dba9534ca 100644 --- a/core/src/epicli/data/common/defaults/configuration/haproxy.yml +++ b/core/src/epicli/data/common/defaults/configuration/haproxy.yml @@ -1,5 +1,5 @@ kind: configuration/haproxy -version: 0.3.0 +version: 0.4.0 title: "HAProxy" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/jmx-exporter.yml b/core/src/epicli/data/common/defaults/configuration/jmx-exporter.yml index d9400bdfb9..e1f021d865 100644 --- a/core/src/epicli/data/common/defaults/configuration/jmx-exporter.yml +++ b/core/src/epicli/data/common/defaults/configuration/jmx-exporter.yml @@ -1,5 +1,5 @@ kind: configuration/jmx-exporter -version: 0.3.0 +version: 0.4.0 title: "JMX exporter" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/kafka-exporter.yml b/core/src/epicli/data/common/defaults/configuration/kafka-exporter.yml index 513c49dfae..ea52e41c57 100644 --- a/core/src/epicli/data/common/defaults/configuration/kafka-exporter.yml +++ b/core/src/epicli/data/common/defaults/configuration/kafka-exporter.yml @@ -1,5 +1,5 @@ kind: configuration/kafka-exporter -version: 0.3.0 +version: 0.4.0 title: "Kafka exporter" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/kafka.yml b/core/src/epicli/data/common/defaults/configuration/kafka.yml index ff0436d2f9..bea8748641 100644 --- a/core/src/epicli/data/common/defaults/configuration/kafka.yml +++ b/core/src/epicli/data/common/defaults/configuration/kafka.yml @@ -1,5 +1,5 @@ kind: configuration/kafka -version: 0.3.0 +version: 0.4.0 title: "Kafka" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/kibana.yml b/core/src/epicli/data/common/defaults/configuration/kibana.yml index de025ea318..54c5388061 100644 --- a/core/src/epicli/data/common/defaults/configuration/kibana.yml +++ b/core/src/epicli/data/common/defaults/configuration/kibana.yml @@ -1,5 +1,5 @@ kind: configuration/kibana -version: 0.3.0 +version: 0.4.0 title: "Kibana" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml b/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml index f7409b0c34..5aa4cfd484 100644 --- a/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml +++ b/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml @@ -1,5 +1,5 @@ kind: configuration/kubernetes-master -version: 0.3.0 +version: 0.4.0 title: "Kubernetes Master Config" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/kubernetes-node.yml b/core/src/epicli/data/common/defaults/configuration/kubernetes-node.yml index f7380dcd51..38c34f4e0d 100644 --- a/core/src/epicli/data/common/defaults/configuration/kubernetes-node.yml +++ b/core/src/epicli/data/common/defaults/configuration/kubernetes-node.yml @@ -1,5 +1,5 @@ kind: configuration/kubernetes-node -version: 0.3.0 +version: 0.4.0 title: "Kubernetes Node Config" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/node-exporter.yml b/core/src/epicli/data/common/defaults/configuration/node-exporter.yml index 9ec92fd03f..fd42bfc406 100644 --- a/core/src/epicli/data/common/defaults/configuration/node-exporter.yml +++ b/core/src/epicli/data/common/defaults/configuration/node-exporter.yml @@ -1,5 +1,5 @@ kind: configuration/node-exporter -version: 0.3.0 +version: 0.4.0 title: "Node exporter" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/postgresql.yml b/core/src/epicli/data/common/defaults/configuration/postgresql.yml index 2e713b612c..6684cf41d7 100644 --- a/core/src/epicli/data/common/defaults/configuration/postgresql.yml +++ b/core/src/epicli/data/common/defaults/configuration/postgresql.yml @@ -1,5 +1,5 @@ kind: configuration/postgresql -version: 0.3.0 +version: 0.4.0 title: "Postgresql" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/prometheus.yml b/core/src/epicli/data/common/defaults/configuration/prometheus.yml index f02fc7caad..990ba7b745 100644 --- a/core/src/epicli/data/common/defaults/configuration/prometheus.yml +++ b/core/src/epicli/data/common/defaults/configuration/prometheus.yml @@ -1,5 +1,5 @@ kind: configuration/prometheus -version: 0.3.0 +version: 0.4.0 title: "Prometheus" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/rabbitmq.yml b/core/src/epicli/data/common/defaults/configuration/rabbitmq.yml index b4ed50fb32..3ae15ad69a 100644 --- a/core/src/epicli/data/common/defaults/configuration/rabbitmq.yml +++ b/core/src/epicli/data/common/defaults/configuration/rabbitmq.yml @@ -1,5 +1,5 @@ kind: configuration/rabbitmq -version: 0.3.0 +version: 0.4.0 title: "RabbitMQ" name: default specification: diff --git a/core/src/epicli/data/common/defaults/configuration/zookeeper.yml b/core/src/epicli/data/common/defaults/configuration/zookeeper.yml index 0455c6c1b8..a44295e238 100644 --- a/core/src/epicli/data/common/defaults/configuration/zookeeper.yml +++ b/core/src/epicli/data/common/defaults/configuration/zookeeper.yml @@ -1,5 +1,5 @@ kind: configuration/zookeeper -version: 0.3.0 +version: 0.4.0 title: "Zookeeper" name: default specification: diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 410ce94eca..30370436dd 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -1,5 +1,5 @@ kind: epiphany-cluster -version: 0.3.0 +version: 0.4.0 title: "Epiphany cluster Config" provider: aws name: "default" diff --git a/core/src/epicli/data/common/defaults/infrastructure/machine.yml b/core/src/epicli/data/common/defaults/infrastructure/machine.yml index 442f153b21..bcc968ef14 100644 --- a/core/src/epicli/data/common/defaults/infrastructure/machine.yml +++ b/core/src/epicli/data/common/defaults/infrastructure/machine.yml @@ -1,5 +1,5 @@ kind: infrastructure/virtual-machine -version: 0.3.0 +version: 0.4.0 title: "Virtual Machine Infra" provider: any name: default diff --git a/core/src/epicli/data/common/validation/core/definitions.yml b/core/src/epicli/data/common/validation/core/definitions.yml index f29dad8567..08bc0ed4fd 100644 --- a/core/src/epicli/data/common/validation/core/definitions.yml +++ b/core/src/epicli/data/common/validation/core/definitions.yml @@ -24,9 +24,9 @@ provider: version: type: string title: The Version Schema - default: '0.3.0' + default: '0.4.0' examples: - - 0.3.0 + - 0.4.0 pattern: ^((\d+\.)(\d+\.)(\d))$ unvalidated_specification: type: diff --git a/core/src/epicli/gen-licenses.py b/core/src/epicli/gen-licenses.py index 78d287973c..e91f00c3cf 100644 --- a/core/src/epicli/gen-licenses.py +++ b/core/src/epicli/gen-licenses.py @@ -1,3 +1,4 @@ +import sys import subprocess import json import os @@ -39,12 +40,20 @@ def _get_recursive_dependencies_for(direct_dependencies: Set[str]) -> Set[str]: res = res | deps return {dependencies_dict[r]['package']['package_name'] for r in res} +def makeRequest(url, token): + request = urllib.request.Request(url) + request.add_header('Authorization', 'token %s' % token) + return urllib.request.urlopen(request) -def get_pkg_data(pkgname: str) -> str: - pkgs = pkg_resources.require(pkgname) +def get_pkg_data(pkgname: str, pat:str) -> str: + print('Processing package: ', pkgname) + try: + pkgs = pkg_resources.require(pkgname) + except: + logging.warning('Failed to get license information for package: ' + pkgname) + return None pkg = pkgs[0] pkg_data = {} - print('Processing package: ', pkgname) for line in pkg.get_metadata_lines('METADATA'): try: (key, value) = line.split(': ', 1) @@ -64,28 +73,36 @@ def get_pkg_data(pkgname: str) -> str: pkg_data['License'] = value home = pkg_data['Home-page'].lower().rstrip('/') + if 'github' in home: try: split = home.split('/') repo = split[len(split)-1] user = split[len(split)-2] - license_data = json.loads(urllib.request.urlopen('https://api.github.com/repos/' + user + '/' + repo + '/license' ).read().decode()) + license_data = json.loads(makeRequest('https://api.github.com/repos/' + user + '/' + repo + '/license', pat).read().decode()) pkg_data['License'] = license_data['license']['name'] - pkg_data['License repo'] = urllib.request.urlopen(license_data['download_url']).read().decode() + pkg_data['License repo'] = makeRequest(license_data['download_url'], pat).read().decode() if license_data['license']['key'] != 'other': - license_text = json.loads(urllib.request.urlopen(license_data['license']['url']).read().decode()) + license_text = json.loads(makeRequest(license_data['license']['url'], pat).read().decode()) pkg_data['License text'] = license_text['body'] except: - logging.warning('Failed to pull in Github license information for package: ', pkgname) + logging.warning('Failed to pull in Github license information for package: ' + pkgname) + return pkg_data def _main() -> None: + pat = sys.argv[1] + if pat == None: + logging.critical('No Github personal access tokens passed as argument.' ) + return direct_dependencies = _get_dependencies_from_pipfile() all_deps = _get_recursive_dependencies_for(direct_dependencies) all_deps_data = [] for dep in all_deps: - all_deps_data.append(get_pkg_data(dep)) + data = get_pkg_data(dep, pat) + if data != None: + all_deps_data.append(data) licenses_content = """ # This is a generated file so don`t change this manually. diff --git a/core/src/epicli/prepare-bds.bat b/core/src/epicli/prepare-bds.bat index 75907ee5fa..1db281b218 100755 --- a/core/src/epicli/prepare-bds.bat +++ b/core/src/epicli/prepare-bds.bat @@ -2,6 +2,6 @@ :: and from that download and build/extract all used python dependencies :: to the externals directory for inclusion with the BDS scan. call build-wheel.bat -pip download --no-clean --no-binary all -d %cd%/external/packages/ --build %cd%/external/ %cd%/dist/epicli-0.3.0-py3-none-any.whl +pip download --no-clean --no-binary all -d %cd%/external/packages/ --build %cd%/external/ %cd%/dist/epicli-0.4.0-py3-none-any.whl rmdir /Q /S %cd%\external\packages\ rmdir /Q /S %cd%\external\epicli\ diff --git a/core/src/epicli/prepare-bds.sh b/core/src/epicli/prepare-bds.sh index 4da5759d23..e3099a1b01 100755 --- a/core/src/epicli/prepare-bds.sh +++ b/core/src/epicli/prepare-bds.sh @@ -2,6 +2,6 @@ # and from that download and build/extract all used python dependencies # to the externals directory for inclusion with the BDS scan. sh ./build-wheel.sh -pip download --no-clean --no-binary all -d $PWD/external/packages/ --build $PWD/external/ $PWD/dist/epicli-0.3.0-py3-none-any.whl +pip download --no-clean --no-binary all -d $PWD/external/packages/ --build $PWD/external/ $PWD/dist/epicli-0.4.0-py3-none-any.whl rm -rf $PWD/external/packages/ rm -rf $PWD/external/epicli/ diff --git a/core/version.sh b/core/version.sh index 5f05f43086..cdeb6366a0 100755 --- a/core/version.sh +++ b/core/version.sh @@ -25,5 +25,5 @@ set -e unset EPIPHANY_VERSION unset EPIPHANY_VERSION_NAME -export EPIPHANY_VERSION="0.3.0" +export EPIPHANY_VERSION="0.4.0" export EPIPHANY_VERSION_NAME="Epiphany" \ No newline at end of file diff --git a/docs/home/SECURITY.md b/docs/home/SECURITY.md index d5f10e3859..94390bbf6d 100644 --- a/docs/home/SECURITY.md +++ b/docs/home/SECURITY.md @@ -5,7 +5,6 @@ - [Users and roles created by Epiphany](#users-and-roles-created-by-epiphany) - [Ports used by components in Epiphany](#ports-used-by-components-in-epiphany) - ### Users and roles created by epiphany By default Epiphany is creating user operations that is used to connect to machines with admin rights. This setting can @@ -24,14 +23,12 @@ Additional to users created by each component Epiphany creates also users and gr Other accounts created by each component you can find in these components documentation. - ### Ports used by components in Epiphany -Below you can find list of ports used by default in Epiphany on per component basis. Some of them can be changed to -different values. +Below you can find list of ports used by default in Epiphany on per component basis. Some of them can be changed to different values. 1. OS services: - + - 22 - ssh 2. Prometheus exporters: diff --git a/docs/home/TESTING.md b/docs/home/TESTING.md index 376a94c6ea..e05b37b120 100644 --- a/docs/home/TESTING.md +++ b/docs/home/TESTING.md @@ -14,13 +14,13 @@ ## Welcome This documentation describe approach in testing for open-source project 'epiphany-platform'. -In this section you can find test strategy, tools used for test management and terminology. +In this section you can find test strategy, tools used for test management and terminology. ## Tool For test management we are using TestQuality, which extends Github to provide modern, powerful, test plan management. All test activities are reported under dedicated project: - + **https://epiphany-platform.testquality.com** On-line help documentation is located: https://epiphany-platform.testquality.com/help/what @@ -55,6 +55,4 @@ f.e _Automatic Deployment Smoke Test Friday 5th of April 2019 08:07:15 AM_ ## Administrators of testquality [Pawel](mailto:erzetpe@gmail.com) [Marek](mailto:marek.peszt@pl.abb.com) -[Przemek](mailto:przemyslaw.dyrda@pl.abb.com) - -``` +[Przemek](mailto:przemyslaw.dyrda@pl.abb.com \ No newline at end of file From df65902cd087ffd33d3473ea7dbbd294247922c2 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 13 Sep 2019 14:43:36 +0200 Subject: [PATCH 37/57] Feature/azure-k8n-storage (#487) - Added shared storage for k8n --- .../epiphany-bld-apps/data.yaml | 2 +- .../epiphany-playground/basic-data.yaml | 2 +- .../epiphany-qa-basic/basic-data.yaml | 2 +- .../epiphany-qa-template/data.yaml.j2 | 2 +- .../epiphany-single-machine/data.yaml | 2 +- .../epiphany-template/data.yaml.j2 | 2 +- core/data/metal/epiphany-lab/data.yaml | 2 +- .../metal/epiphany-single-machine/data.yaml | 2 +- .../cli/engine/providers/azure/APIProxy.py | 9 ++++++- .../providers/azure/InfrastructureBuilder.py | 20 ++++++++++---- .../azure/InfrastructureConfigCollector.py | 20 ++++++++++++-- .../defaults/infrastructure/storage-share.yml | 9 +++++++ .../terraform/infrastructure/storage-share.j2 | 27 +++++++++++++++++++ .../infrastructure/storage-share.yml | 1 + .../tasks/azure/kubernetes-storage.yml | 17 ++++++++++++ .../azure/k8s-persistent-volume-claim.yml.j2 | 12 +++++++++ .../azure/k8s-persistent-volume.yml.j2 | 8 ++++-- .../templates/azure/k8s-storage-secret.yml.j2 | 4 +-- .../configuration/kubernetes-master.yml | 2 +- .../azure/test_AzureConfigBuilder.py | 14 +++++++++- 20 files changed, 137 insertions(+), 22 deletions(-) create mode 100644 core/src/epicli/data/azure/defaults/infrastructure/storage-share.yml create mode 100644 core/src/epicli/data/azure/terraform/infrastructure/storage-share.j2 create mode 100644 core/src/epicli/data/azure/validation/infrastructure/storage-share.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume-claim.yml.j2 diff --git a/core/data/azure/infrastructure/epiphany-bld-apps/data.yaml b/core/data/azure/infrastructure/epiphany-bld-apps/data.yaml index 8e1037302a..b41e9f5837 100644 --- a/core/data/azure/infrastructure/epiphany-bld-apps/data.yaml +++ b/core/data/azure/infrastructure/epiphany-bld-apps/data.yaml @@ -8,7 +8,7 @@ title: Epiphany Apps Infrastructure... kind: datafile -version: 0.3.0 +version: 0.4.0 # NOTE: Any data values that are empty put "" or the value None will be used in the templates for those attributes. diff --git a/core/data/azure/infrastructure/epiphany-playground/basic-data.yaml b/core/data/azure/infrastructure/epiphany-playground/basic-data.yaml index b1dea06854..8b63fa4e6e 100644 --- a/core/data/azure/infrastructure/epiphany-playground/basic-data.yaml +++ b/core/data/azure/infrastructure/epiphany-playground/basic-data.yaml @@ -2,7 +2,7 @@ # Simplified datafile that you can use together with template (see README.md in this folder). # Change values according to your needs, start with generating ssh keys and placing them in the directory "keys_directory". Do not forget to update "keys_directory" as well. kind: simplified-datafile -version: 0.3.0 +version: 0.4.0 environment_name: Playground azure: subscription_name: YOUR-SUBSCRIPTION-NAME diff --git a/core/data/azure/infrastructure/epiphany-qa-basic/basic-data.yaml b/core/data/azure/infrastructure/epiphany-qa-basic/basic-data.yaml index 920f312b6a..3c421b124f 100644 --- a/core/data/azure/infrastructure/epiphany-qa-basic/basic-data.yaml +++ b/core/data/azure/infrastructure/epiphany-qa-basic/basic-data.yaml @@ -1,7 +1,7 @@ --- # Simplified datafile that you can use together with QA template. kind: simplified-datafile -version: 0.3.0 +version: 0.4.0 environment_name: {{ resource_group }} azure: subscription_name: {{ sp_subscription_name }} diff --git a/core/data/azure/infrastructure/epiphany-qa-template/data.yaml.j2 b/core/data/azure/infrastructure/epiphany-qa-template/data.yaml.j2 index d837d1a5ab..3a862e11bb 100644 --- a/core/data/azure/infrastructure/epiphany-qa-template/data.yaml.j2 +++ b/core/data/azure/infrastructure/epiphany-qa-template/data.yaml.j2 @@ -9,7 +9,7 @@ title: Epiphany ({{ azure.image_offer }}) {{ environment_name }} kind: datafile -version: 0.3.0 +version: 0.4.0 # NOTE: Any data values that are empty put "" or the value None will be used in the templates for those attributes. diff --git a/core/data/azure/infrastructure/epiphany-single-machine/data.yaml b/core/data/azure/infrastructure/epiphany-single-machine/data.yaml index 39b2b886f1..97dd3f3edc 100644 --- a/core/data/azure/infrastructure/epiphany-single-machine/data.yaml +++ b/core/data/azure/infrastructure/epiphany-single-machine/data.yaml @@ -8,7 +8,7 @@ title: Epiphany Single Machine Infrastructure... kind: datafile -version: 0.3.0 +version: 0.4.0 # NOTE: Any data values that are empty put "" or the value None will be used in the templates for those attributes. diff --git a/core/data/azure/infrastructure/epiphany-template/data.yaml.j2 b/core/data/azure/infrastructure/epiphany-template/data.yaml.j2 index d8f8a9d767..de845e75e9 100644 --- a/core/data/azure/infrastructure/epiphany-template/data.yaml.j2 +++ b/core/data/azure/infrastructure/epiphany-template/data.yaml.j2 @@ -9,7 +9,7 @@ title: Epiphany ({{ azure.image_offer }}) {{ environment_name }} kind: datafile -version: 0.3.0 +version: 0.4.0 # NOTE: Any data values that are empty put "" or the value None will be used in the templates for those attributes. diff --git a/core/data/metal/epiphany-lab/data.yaml b/core/data/metal/epiphany-lab/data.yaml index 120c691f41..fdad10cce6 100644 --- a/core/data/metal/epiphany-lab/data.yaml +++ b/core/data/metal/epiphany-lab/data.yaml @@ -4,7 +4,7 @@ kind: datafile -version: 0.3.0 +version: 0.4.0 # This will apply to a VPN like environment or an air-gapped like environment bastian: diff --git a/core/data/metal/epiphany-single-machine/data.yaml b/core/data/metal/epiphany-single-machine/data.yaml index 271e69987c..c32ba8df7b 100644 --- a/core/data/metal/epiphany-single-machine/data.yaml +++ b/core/data/metal/epiphany-single-machine/data.yaml @@ -4,7 +4,7 @@ kind: datafile -version: 0.3.0 +version: 0.4.0 # This will apply to a VPN like environment or an air-gapped like environment bastian: diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index df9454f2f0..4745851e81 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -10,6 +10,9 @@ class APIProxy: def __init__(self, cluster_model, config_docs): self.cluster_model = cluster_model + self.cluster_name = self.cluster_model.specification.name.lower() + self.cluster_prefix = self.cluster_model.specification.prefix.lower() + self.resource_group_name = resource_name(self.cluster_prefix, self.cluster_name, 'rg') self.config_docs = config_docs self.logger = Log(__name__) @@ -43,7 +46,7 @@ def create_sp(self, app_name, subscription_id): def get_ips_for_feature(self, component_key): look_for_public_ip = self.cluster_model.specification.cloud.use_public_ips - cluster = f'{self.cluster_model.specification.prefix.lower()}-{self.cluster_model.specification.name.lower()}' + cluster = f'{self.cluster_prefix}-{self.cluster_name}' running_instances = self.run(self, f'az vm list-ip-addresses --ids $(az resource list --query "[?type==\'Microsoft.Compute/virtualMachines\' && tags.{component_key} == \'\' && tags.cluster == \'{cluster}\'].id" --output tsv)') result = [] for instance in running_instances: @@ -57,6 +60,10 @@ def get_ips_for_feature(self, component_key): result.append(AnsibleHostModel(name, ip)) return result + def get_storage_account_primary_key(self, storage_account_name): + keys = self.run(self, f'az storage account keys list -g {self.resource_group_name} -n {storage_account_name}') + return keys[0]['value'] + @staticmethod def wait(self, seconds): for x in range(0, seconds): diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 6fe7054080..54e5c880df 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -1,4 +1,5 @@ import os +import uuid from copy import deepcopy from cli.helpers.Step import Step @@ -28,6 +29,9 @@ def run(self): vnet = self.get_virtual_network() infrastructure.append(vnet) + shared_storage = self.get_storage_share_config() + infrastructure.append(shared_storage) + for component_key, component_value in self.cluster_model.specification.components.items(): vm_count = component_value['count'] if vm_count < 1: @@ -139,7 +143,13 @@ def get_public_ip(self, component_key, component_value, vm_config, index): public_ip.specification.allocation_method = vm_config.specification.network_interface.public_ip.allocation_method public_ip.specification.idle_timeout_in_minutes = vm_config.specification.network_interface.public_ip.idle_timeout_in_minutes public_ip.specification.sku = vm_config.specification.network_interface.public_ip.sku - return public_ip + return public_ip + + def get_storage_share_config(self): + storage_share = self.get_config_or_default(self.docs, 'infrastructure/storage-share') + storage_share.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'k8s-ss') + storage_share.specification.storage_account_name = self.cluster_prefix + self.cluster_name + 'k8s' + return storage_share def get_vm(self, component_key, component_value, vm_config, network_interface_name, index): vm = dict_to_objdict(deepcopy(vm_config)) @@ -149,11 +159,11 @@ def get_vm(self, component_key, component_value, vm_config, network_interface_na vm.specification.tags.append({'cluster': f'{self.cluster_prefix}-{self.cluster_name}'}) vm.specification.tags.append({component_key: ''}) if vm.specification.os_type == 'linux': - # For linux we dont need a PW since we only support SSH so just add something random. - vm.specification.admin_password = "NeverGonnaNeed!" + # For linux we dont need a PW since we only support SSH. We add something random for Terraform + # to run and later disable password access in Ansible. + vm.specification.admin_password = str(uuid.uuid4()) if vm_config.specification.os_type == 'windows': - #TODO: We need PW or can we support SSH or something different on Windows? - vm.specification.admin_password = 'TODO' + raise NotImplementedError('Windows VMs not supported jet.') pub_key_path = self.cluster_model.specification.admin_user.key_path + '.pub' if os.path.isfile(pub_key_path): vm.specification.public_key = pub_key_path diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py index 36e677f4a7..7d51943938 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureConfigCollector.py @@ -1,5 +1,6 @@ from cli.helpers.Step import Step -from cli.helpers.doc_list_helpers import select_single +from cli.engine.providers.azure.APIProxy import APIProxy +from cli.helpers.doc_list_helpers import select_single, select_first class InfrastructureConfigCollector(Step): @@ -17,4 +18,19 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) def run(self): - pass + with APIProxy(self.cluster_model, self.docs) as proxy: + self.apply_file_share_for_k8s_pv(proxy) + + def apply_file_share_for_k8s_pv(self, proxy): + storage_share_config = select_first(self.docs, lambda x: x.kind == 'infrastructure/storage-share') + kubernetes_config = select_first(self.docs, lambda x: x.kind == 'configuration/kubernetes-master') + + if self.should_apply_storage_settings(storage_share_config, kubernetes_config): + primary_key = proxy.get_storage_account_primary_key(storage_share_config.specification.storage_account_name) + kubernetes_config.specification.storage.data = { + 'storage_account_name': storage_share_config.specification.storage_account_name, + 'storage_account_key': primary_key + } + + def should_apply_storage_settings(self, storage_share_config, kubernetes_config): + return storage_share_config is not None and kubernetes_config is not None diff --git a/core/src/epicli/data/azure/defaults/infrastructure/storage-share.yml b/core/src/epicli/data/azure/defaults/infrastructure/storage-share.yml new file mode 100644 index 0000000000..a376f7caed --- /dev/null +++ b/core/src/epicli/data/azure/defaults/infrastructure/storage-share.yml @@ -0,0 +1,9 @@ +kind: infrastructure/storage-share +version: 0.4.0 +title: "Azure shared storage" +provider: azure +name: default +specification: + name: SET_BY_AUTOMATION + storage_account_name: SET_BY_AUTOMATION + quota: 50 \ No newline at end of file diff --git a/core/src/epicli/data/azure/terraform/infrastructure/storage-share.j2 b/core/src/epicli/data/azure/terraform/infrastructure/storage-share.j2 new file mode 100644 index 0000000000..a032d642a3 --- /dev/null +++ b/core/src/epicli/data/azure/terraform/infrastructure/storage-share.j2 @@ -0,0 +1,27 @@ +##################################################### +# DO NOT Modify by hand - Managed by Automation +##################################################### +##################################################### +# This file can be used as a base template to build other Terraform files. It attempts to use as much +# Terraform interprolation as possible by creating Terraform variables instead of changing inline +# this approach provides an easier way to do creative looping, fetch IDs of created resources etc. +##################################################### +##################################################### +# {{ specification.name }} +##################################################### +##################################################### + +resource "azurerm_storage_account" "{{ specification.storage_account_name }}" { + name = "{{ specification.storage_account_name }}" + resource_group_name = "${azurerm_resource_group.rg.name}" + location = "${azurerm_resource_group.rg.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_share" "{{ specification.name }}" { + name = "k8s" + resource_group_name = "${azurerm_resource_group.rg.name}" + storage_account_name = "${azurerm_storage_account.{{ specification.storage_account_name }}.name}" + quota = "{{ specification.quota }}" +} \ No newline at end of file diff --git a/core/src/epicli/data/azure/validation/infrastructure/storage-share.yml b/core/src/epicli/data/azure/validation/infrastructure/storage-share.yml new file mode 100644 index 0000000000..89807aa970 --- /dev/null +++ b/core/src/epicli/data/azure/validation/infrastructure/storage-share.yml @@ -0,0 +1 @@ +$ref: '#/definitions/unvalidated_specification' \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/azure/kubernetes-storage.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/azure/kubernetes-storage.yml index d405590361..09a36473ad 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/azure/kubernetes-storage.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/azure/kubernetes-storage.yml @@ -16,6 +16,15 @@ group: "{{ admin_user.name }}" mode: 0644 +- name: Upload k8s persistent volume claim yaml + become: yes + template: + dest: "/home/{{ admin_user.name }}/k8s-persistent-volume-claim.yml" + src: azure/k8s-persistent-volume-claim.yml.j2 + owner: "{{ admin_user.name }}" + group: "{{ admin_user.name }}" + mode: 0644 + - name: apply secret yml become_user: "{{ admin_user.name }}" environment: @@ -31,3 +40,11 @@ shell: "kubectl apply -f /home/{{ admin_user.name }}/k8s-persistent-volume.yml" when: - groups['kubernetes_master'][0] == inventory_hostname + +- name: Apply storage claim yml + become_user: "{{ admin_user.name }}" + environment: + KUBECONFIG: "/home/{{ admin_user.name }}/.kube/config" + shell: "kubectl apply -f /home/{{ admin_user.name }}/k8s-persistent-volume-claim.yml" + when: + - groups['kubernetes_master'][0] == inventory_hostname diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume-claim.yml.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume-claim.yml.j2 new file mode 100644 index 0000000000..93fe259429 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume-claim.yml.j2 @@ -0,0 +1,12 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ specification.storage.name }}-claim +spec: + storageClassName: azurefile + volumeName: {{ specification.storage.name }} + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ specification.storage.capacity }}Gi diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume.yml.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume.yml.j2 index 978ab3d485..611316ac47 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume.yml.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-persistent-volume.yml.j2 @@ -1,10 +1,14 @@ apiVersion: "v1" kind: "PersistentVolume" metadata: - name: "pv0001" +metadata: + name: {{ specification.storage.name }} + labels: + name: {{ specification.storage.name }} spec: + storageClassName: azurefile capacity: - storage: "15Gi" + storage: {{ specification.storage.capacity }}Gi accessModes: - "ReadWriteMany" azureFile: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-storage-secret.yml.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-storage-secret.yml.j2 index 706db80cd9..9de9476392 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-storage-secret.yml.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/azure/k8s-storage-secret.yml.j2 @@ -4,5 +4,5 @@ metadata: name: azure-secret type: Opaque data: - azurestorageaccountname: {{ kubernetes.storage.account | b64encode }} - azurestorageaccountkey: {{ kubernetes.storage.key | b64encode }} \ No newline at end of file + azurestorageaccountname: {{ specification.storage.data.storage_account_name | b64encode }} + azurestorageaccountkey: {{ specification.storage.data.storage_account_key | b64encode }} \ No newline at end of file diff --git a/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml b/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml index 5aa4cfd484..b564a04b7a 100644 --- a/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml +++ b/core/src/epicli/data/common/defaults/configuration/kubernetes-master.yml @@ -27,7 +27,7 @@ specification: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 - plugin: calico # valid options: calico, flannel, canal (due to lack of support for calico on Azure - use canal) + plugin: flannel # valid options: calico, flannel, canal (due to lack of support for calico on Azure - use canal) imageRepository: k8s.gcr.io certificatesDir: /etc/kubernetes/pki etcd_args: diff --git a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py index 3846547fd2..1129cc232e 100644 --- a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py @@ -40,10 +40,11 @@ def test_get_subnet_should_set_proper_values_to_model(): }) builder = InfrastructureBuilder([cluster_model]) - actual = builder.get_subnet(subnet_definition, 'component', 1) + actual = builder.get_subnet(subnet_definition, 'component', 'prefix-testcluster-component-sg-1', 1) assert actual.specification.name == 'prefix-testcluster-component-subnet-1' assert actual.specification.address_prefix == subnet_definition['address_pool'] + assert actual.specification.security_group_name == 'prefix-testcluster-component-sg-1' assert actual.specification.cluster_name == 'testcluster' @@ -105,6 +106,17 @@ def test_get_network_interface_should_set_proper_values_to_model(): assert actual.specification.enable_accelerated_networking == False +def test_get_storage_share_config_should_set_proper_values_to_model(): + cluster_model = get_cluster_model(cluster_name='TestCluster') + builder = InfrastructureBuilder([cluster_model]) + + actual = builder.get_storage_share_config() + + assert actual.specification.name == 'prefix-testcluster-k8s-ss' + assert actual.specification.storage_account_name == 'prefixtestclusterk8s' + assert actual.specification.quota == 50 + + def get_cluster_model(address_pool='10.22.0.0/22', cluster_name='EpiphanyTestCluster'): cluster_model = dict_to_objdict({ 'kind': 'epiphany-cluster', From 017f5cf7d810fa6327df13ac75ce49dfb21439b5 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Thu, 19 Sep 2019 14:10:23 +0200 Subject: [PATCH 38/57] Azure rehat fixes (#511) Fix for container-selinux package on redhat. Fixes for HAProxy and Posgress on Azure. Fix for running tests from VSCode. --- .../ansible/playbooks/roles/docker/tasks/RedHat.yml | 4 ++-- .../ansible/playbooks/roles/haproxy/tasks/RedHat.yml | 10 ++++++++-- .../playbooks/roles/postgresql/tasks/RedHat.yml | 10 ++++++++-- core/src/epicli/tests/cli/conftest.py | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml index ae293162f1..4560ac582f 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml @@ -9,14 +9,14 @@ - name: Install container-selinux for RHEL 7.6 and later yum: - name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.99-1.el7_6.noarch.rpm + name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.107-1.el7_6.noarch.rpm state: present update_cache: yes when: ansible_distribution_version is version('7.6', '>=') - name: Install container-selinux for 7.5 and older yum: - name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.74-1.el7.noarch.rpm + name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.107-3.el7.noarch.rpm state: present update_cache: yes when: ansible_distribution_version is version('7.5', '<=') diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml index 8cc4fe36bc..8b181d86b8 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml @@ -15,12 +15,16 @@ stat: path: /etc/yum.repos.d/redhat-rhui.repo register: rhui_exist + when: + - specification.provider == "aws" - name: Check if Software Collections repository on EC2 exists shell: grep -c -i rhui-REGION-rhel-server-rhscl /etc/yum.repos.d/redhat-rhui.repo register: sc_repo_count failed_when: "sc_repo_count.rc == 2" - when: rhui_exist + when: + - specification.provider == "aws" + - rhui_exist - name: Enable Software Collections on EC2 ini_file: @@ -28,7 +32,9 @@ section: rhui-REGION-rhel-server-rhscl option: enabled value: 1 - when: sc_repo_count.stdout|int == 1 + when: + - specification.provider == "aws" + - sc_repo_count.stdout|int == 1 - name: Install haproxy family packages yum: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml index 7da233a37c..8e5d187a0e 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml @@ -5,12 +5,16 @@ stat: path: /etc/yum.repos.d/redhat-rhui.repo register: rhui_exist + when: + - specification.provider == "aws" - name: Check if Software Collections repository on EC2 exists shell: grep -c -i rhui-REGION-rhel-server-rhscl /etc/yum.repos.d/redhat-rhui.repo register: sc_repo_count failed_when: "sc_repo_count.rc == 2" - when: rhui_exist + when: + - specification.provider == "aws" + - rhui_exist - name: Enable Software Collections on EC2 ini_file: @@ -18,7 +22,9 @@ section: rhui-REGION-rhel-server-rhscl option: enabled value: 1 - when: sc_repo_count.stdout|int == 1 + when: + - specification.provider == "aws" + - sc_repo_count.stdout|int == 1 - name: Install postgresql family packages yum: diff --git a/core/src/epicli/tests/cli/conftest.py b/core/src/epicli/tests/cli/conftest.py index b4963f09e1..ff14f818da 100644 --- a/core/src/epicli/tests/cli/conftest.py +++ b/core/src/epicli/tests/cli/conftest.py @@ -7,7 +7,7 @@ def pytest_configure(config): This hook is called for every plugin and initial conftest file after command line options have been parsed. """ - Config().output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '/results/') + Config().output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'results/') def pytest_sessionstart(session): From 761ebc026c7ab4231a38f530f1912c3b4c046d4a Mon Sep 17 00:00:00 2001 From: Samir Alajmovic Date: Tue, 24 Sep 2019 09:42:58 +0200 Subject: [PATCH 39/57] Fix typo rabbitmq (#518) --- .../data/common/defaults/configuration/feature-mapping.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml index be55a11932..aed28c2cd6 100644 --- a/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml +++ b/core/src/epicli/data/common/defaults/configuration/feature-mapping.yml @@ -85,7 +85,7 @@ specification: - elasticsearch-curator single_machine: - kubernetes-master - - rabbitmql + - rabbitmq - postgresql kubernetes_master: - kubernetes-master From 99914c432c7e789b39c6113c6cd48e1abeb940af Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Wed, 25 Sep 2019 10:01:16 +0200 Subject: [PATCH 40/57] Fix/rabbitmq error (#523) - Fixed typo for rabbitmq machine --- .../data/azure/defaults/infrastructure/virtual-machine.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml index 38af52c9e0..8aec07e5a7 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml @@ -358,7 +358,7 @@ kind: infrastructure/virtual-machine version: 0.4.0 title: "Virtual Machine Infra" provider: azure -name: rabbit-machine +name: rabbitmq-machine specification: size: Standard_DS2_v2 security: From 9db25b74acdb8004202e388fa0b663dda9401948 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 25 Sep 2019 11:00:49 +0200 Subject: [PATCH 41/57] Fixed link to container-selinux package (legacy) (#525) * Fixed link to container-selinux package --- core/core/src/ansible/roles/docker/tasks/RedHat.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/core/src/ansible/roles/docker/tasks/RedHat.yml b/core/core/src/ansible/roles/docker/tasks/RedHat.yml index eeee04aa9d..7d6ef0aac0 100644 --- a/core/core/src/ansible/roles/docker/tasks/RedHat.yml +++ b/core/core/src/ansible/roles/docker/tasks/RedHat.yml @@ -11,7 +11,7 @@ # Todo: Investigate problems with container selinux on Azure. - name: Install container packages yum: - name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.95-2.el7_6.noarch.rpm + name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.107-1.el7_6.noarch.rpm state: present update_cache: yes From 4fca543d0dc6b1f050b6bcce5aae6b1cc46f6919 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 27 Sep 2019 14:17:07 +0200 Subject: [PATCH 42/57] Feature/document updates (#524) - Restructure documentation separating Epicli and Legacy - Broke down HOWTO document in separate documents - Updated readme.md - Fixed docker tag/run commands with TAG information. - Added 'How to create an Epiphany cluster on existing infrastructure' article for Epicli - Added article to delete a cluster from a cloud provider - Started with an Article to create a cloud provider - Added 'How to create an Epiphany cluster on a cloud provider' for Epicli --- README.md | 11 +- docs/home/DEVELOPMENT.md | 2 +- docs/home/HOWTO.md | 1809 ++---------------------------- docs/home/RESOURCES.md | 1 + docs/home/TROUBLESHOOTING.md | 36 +- docs/home/howto/CLUSTER.md | 413 +++++++ docs/home/howto/DATABASES.md | 32 + docs/home/howto/KUBERNETES.md | 197 ++++ docs/home/howto/MONITORING.md | 164 +++ docs/home/howto/PREREQUISITES.md | 274 +++++ docs/home/howto/RETENTION.md | 145 +++ docs/home/howto/SECURITY.md | 211 ++++ docs/home/howto/UPGRADE.md | 457 ++++++++ 13 files changed, 2013 insertions(+), 1739 deletions(-) create mode 100644 docs/home/howto/CLUSTER.md create mode 100644 docs/home/howto/DATABASES.md create mode 100644 docs/home/howto/KUBERNETES.md create mode 100644 docs/home/howto/MONITORING.md create mode 100644 docs/home/howto/PREREQUISITES.md create mode 100644 docs/home/howto/RETENTION.md create mode 100644 docs/home/howto/SECURITY.md create mode 100644 docs/home/howto/UPGRADE.md diff --git a/README.md b/README.md index 78739fa2fb..2d4c6d0d8a 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,16 @@ Epiphany can run on as few as one node (laptop, desktop, server) but the real va We currently use Terraform and Ansible for our automation orchestration. All automation is idempotent so you can run it as many times as you wish and it will maintain the same state unless you change the data. If someone makes a "snow flake" change to the environment (you should never do this) then simply running the automation again will put the environment back to the desired state. -## Legacy note +## Note about legacy Epiphany -In Epiphany 0.3 a new CLI tool was introduced (epicli) for deploying and managing clusters and currently supports AWS and bare metal deployment. Azure support will be added soon in a subsequent release but for now if you are in need for deploying a cluster on Azure use the older Legacy engine. +Epicli 0.4.0 adds support for Azure deployments so using legacy Epiphany is no longer needed. We advice new projects to start straight with Epicli and older projects which still use legacy Epiphany to move over to Epicli 0.4.0. A tool to migrate legacy data files to the new format is in the works and will be released shortly. + +The Epicli 0.5.0 release later this year will drop the inclusion of the legacy path entirely. + +## Note about documentation + +- The documentation is a moving target. Always check the latest documentation on the develop branch. There is a big chance that whatever you are looking for is already added/updated or improved there. +- We are currently in the process of documenting all features of Epicli and phasing out legacy Epiphany documentation. When documentation is specific for `Epicli` or `Legacy` it will be marked under a header with the these names. If its not under any of these headers then it applies to both. ## Quickstart diff --git a/docs/home/DEVELOPMENT.md b/docs/home/DEVELOPMENT.md index 2779789793..d02e88c587 100644 --- a/docs/home/DEVELOPMENT.md +++ b/docs/home/DEVELOPMENT.md @@ -167,7 +167,7 @@ There is one launch configuration called ```server spec tests```. This launch co "type": "python", "request": "launch", "program": "${workspaceFolder}/run-tests.py", - "cwd": "${workspaceFolder}", + "cwd": "${workspaceFolder}", "pythonPath": "${config:python.pythonPath}", "env": { "PYTHONPATH": "${workspaceFolder}" }, "console": "integratedTerminal", diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index e9f89d6f0b..2880ecab32 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -1,1720 +1,93 @@ # How-To Guides -## Contents - -- [Prerequisites for Epiphany engine](#prerequisites-to-run-epiphany-engine) - - [Epicli](#epicli) - - [Run Epicli directly from OS](#run-epicli-directly-from-os) - - [Run Epicli from Docker image](#run-epicli-from-docker-image) - - [Legacy](#legacy) - - [Run directly from OS](#run-directly-from-os) - - [Run Docker image for development](#run-docker-image-for-development) - - [Run Docker image for deployment](#run-docker-image-for-deployment) - - [Note for Windows users](#note-for-windows-users) -- Epiphany cluster - - [How to create an Epiphany cluster on premise](#how-to-create-an-epiphany-cluster-on-premise) - - [How to create an Epiphany cluster on Azure](#how-to-create-an-epiphany-cluster-on-azure) - - [How to create production environment on Azure](#how-to-create-production-environment-on-azure) - - [Build artifacts](#build-artifacts) - - [How to scale Kubernetes and Kafka](#how-to-scale-kubernetes-and-kafka) - - [Kafka replication and partition setting](#kafka-replication-and-partition-setting) - - [RabbitMQ installation and setting](#rabbitmq-installation-and-setting) - - [Single machine cluster](#single-machine-cluster) -- Monitoring - - [Import and create of Grafana dashboards](#import-and-create-of-grafana-dashboards) - - [How to configure Kibana](#how-to-configure-kibana) - - [How to configure Prometheus alerts](#how-to-configure-prometheus-alerts) - - [How to configure scalable Prometheus setup](#how-to-configure-scalable-prometheus-setup) - - [How to configure Azure additional monitoring and alerting](#how-to-configure-azure-additional-monitoring-and-alerting) -- Kubernetes - - [How to do Kubernetes RBAC](#how-to-do-kubernetes-rbac) - - [How to run an example app](#how-to-run-an-example-app) - - [How to set resource requests and limits for Containers](#how-to-set-resource-requests-and-limits-for-containers) - - [How to run CronJobs](#how-to-run-cronjobs) - - [How to test the monitoring features](#how-to-test-the-monitoring-features) - - [How to run chaos on Epiphany Kubernetes cluster and monitor it with Grafana](#how-to-run-chaos-on-epiphany-kubernetes-cluster-and-monitor-it-with-grafana) - - [How to tunnel Kubernetes dashboard from remote kubectl to your PC](#how-to-tunnel-kubernetes-dashboard-from-remote-kubectl-to-your-pc) - - [How to setup Azure VM as docker machine for development](#how-to-setup-azure-vm-as-docker-machine-for-development) - - [How to upgrade Kubernetes cluster](#how-to-upgrade-kubernetes-cluster) - - [How to upgrade Kubernetes cluster from 1.13.0 to 1.13.1](#how-to-upgrade-kubernetes-cluster-from-1130-to-1131) - - [How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch](#how-to-upgrade-kubernetes-cluster-from-1131-to-11310--latest-patch) - - [How to authenticate to Azure AD app](#how-to-authenticate-to-azure-ad-app) - - [How to expose service through HA Proxy load balancer](#how-to-expose-service-through-ha-proxy-load-balancer) -- Security - - [How to use TLS/SSL certificate with HA Proxy](#how-to-use-tls/ssl-certificate-with-ha-proxy) - - [How to use Kubernetes Secrets](#how-to-use-kubernetes-secrets) - - [How to enable or disable network traffic - firewall](#how-to-enable-or-disable-network-traffic) - - [Client certificate for Azure VPN connection](#client-certificate-for-azure-vpn-connection) - - [How to enable AWS disk encryption](#how-to-enable-AWS-disk-encryption) -- [Data and log retention](#data-and-log-retention) - - [Elasticsearch](#elasticsearch) - - [Grafana](#grafana) - - [Kafka](#kafka) - - [Kibana](#kibana) - - [Kubernetes](#kubernetes) - - [Prometheus](#prometheus) - - [Zookeeper](#zookeeper) -- Databases - - [How to configure PostgreSQL](#how-to-configure-postgresql) - - [How to configure PostgreSQL replication](#how-to-configure-postgresql-replication) - -## Prerequisites to run Epiphany engine - -### Epicli - -#### Run Epicli directly from OS - -1. To be able to run the Epicli from your local OS you have to install: - - - Python 3.7 - - PIP - - Pipenv - -2. Open a terminal in `/core/src/epicli` and run: - - ```bash - pipenv install - ``` - - This will create a virtual Python 3.7 environment and install all needed dependencies. - -3. Build the Epicli wheel: - - ```bash - ./build-wheel.sh - ``` - -4. Enter the virtual Python enviroment: - - ```bash - pipenv shell - ``` - -5. Install the Epicli wheel inside the virtual enviroment: - - ```bash - pip install dist/epicli-VERSION-py3-none-any.whl - ``` - -6. Verify the Epicli installation: - - ```bash - epicli --version - ``` - - This should return the version of the CLI deployed. - -Now you can use Epicli inside the created virtual environment. - -#### Run Epicli from Docker image - -There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. - -##### Build Epicli image locally - -1. Install the following dependencies: - - - Python 3.7 - - PIP - - Pipenv - - Docker - -2. Open a terminal in `/core/src/epicli` and run: - - On Linux: - - ```bash - ./build-docker.sh - ``` - - On windows: - - ```bash - ./build-docker.bat - ``` - -##### Pull Epicli image from the registry - -```bash -docker pull epiphanyplatform/epicli -``` - -##### Running the Epicli image - -To run the image: - -Locally build: - -```bash -docker run -it -v LOCAL_DIR:/shared --rm epicli -``` - -Pulled: - -```bash -docker run -it -v LOCAL_DIR:/shared --rm epiphanyplatform/epicli -``` - -Where `LOCAL_DIR` should be replaced with the local path to the directory for Epicli input (SSH keys, data yamls) and output (logs, build states). - -### Legacy - -#### Run directly from OS - -To be able to run the Epiphany engine from your local OS you have to install: - -- Bash 4.4+ - - Should be natively installed on Linux distributions. - - MacOS version of bash most likely needs upgrading. - - For Windows 10 you can install Ubuntu subsystem. - - For Windows 7 see the docker image options below. -- Ansible 2.6+ -- Hashicorp Terraform 0.11.8+ -- jq (JSON Query tool: ) -- Python 2.7 - - jinja2 2.10+ - - jmespath 0.9.3+ -- Git -- Azure CLI 2.0+ -- SSH - -This can both be used for deploying/managing clusters or for development. - -#### Run Docker image for development - -To facilitate an easier path for developers to contribute to Epiphany we have a development docker image based on alpine. This image will help to more easily setup a development environment or to develop on systems which do not support Bash like Windows 7. - -The following prerequisites are needed when working with the development image: - -- Docker - - For Windows 7 check [here](https://docs.docker.com/toolbox/toolbox_install_windows) -- Git - -There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. - -##### Build dev image locally - -```bash -docker build -t epiphany-dev -f core/src/docker/dev/Dockerfile . -``` - -##### Pull dev image from the registry - -```bash -docker pull epiphanyplatform/epiphany-dev -``` - -##### Running the dev image - -To run the image: - -Locally build: - -```bash -docker run -it -v LOCAL_DEV_DIR:/epiphany --rm epiphany-dev -``` - -Pulled: - -```bash -docker run -it -v LOCAL_DEV_DIR:/epiphany --rm epiphanyplatform/epiphany-dev -``` - -Where `LOCAL_DEV_DIR` should be replaced with the local path to your local Epiphany repo. This will then be mapped to `epiphany` inside the container. If everything is ok you will be presented with a Bash prompt from which one can run the Epiphany engine while editing the core and data sources on the local OS. Note that when filling in your data YAMLs one needs to specify the paths from the container's point of view. - -#### Run Docker image for deployment - -For people who are only using the Epiphany engine to deploy and maintain clusters there is a Dockerfile for the image with the engine already embedded. - -There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. - -##### Build deployment image locally - -```bash -docker build -t epiphany-dev -f core/src/docker/deploy/Dockerfile . -``` - -##### Pull deployment image from the registry - -```bash -docker pull epiphanyplatform/epiphany-deploy -``` - -##### Running the deployment image - -To run the image: - -Locally build: - -```bash -docker run -it -v LOCAL_DATA_DIR:/epiphany/core/data \ - -v LOCAL_BUILD_DIR:/epiphany/core/build \ - -v LOCAL_SSH_DIR:/epiphany/core/ssh \ - --rm epiphany-deploy -``` - -Pulled: - -```bash -docker run -it -v LOCAL_DATA_DIR:/epiphany/core/data \ - -v LOCAL_BUILD_DIR:/epiphany/core/build \ - -v LOCAL_SSH_DIR:/epiphany/core/ssh \ - --rm epiphanyplatform/epiphany-deploy -``` - -```LOCAL_DATA_DIR``` should be the host input directy for your data YAMLs and certificates. ```LOCAL_BUILD_DIR``` should be the host directory where you want the Epiphany engine to write its build output. ```LOCAL_SSH_DIR``` should be the host directory where the SSH keys are stored. If everything is ok you will be presented with a Bash prompt from which one can run the Epiphany engine. Note that when filling in your data YAMLs one needs to specify the paths from the container's point of view. - -[`Azure specific`] Ensure that you have already enough resources/quotas accessible in your region/subscription on Azure before you run Epiphany - depending on your configuration it can create large number of resources. - -### Note for Windows users - -- Watch out for the line endings conversion. By default Git for Windows sets `core.autocrlf=true`. Mounting such files with Docker results in `^M` end-of-line character in the config files. -Use: [Checkout as-is, commit Unix-style](https://stackoverflow.com/questions/10418975/how-to-change-line-ending-settings) (`core.autocrlf=input`) or Checkout as-is, commit as-is (`core.autocrlf=false`). Be sure to use a text editor that can work with Unix line endings (e.g. Notepad++). - -- Remember to allow Docker Desktop to mount drives in Settings -> Shared Drives - -- Escape your paths properly: - - - Powershell example: - ```bash - docker run -it -v C:\Users\USERNAME\git\epiphany:/epiphany --rm epiphany-dev - ``` - - Git-Bash example: - ```bash - winpty docker run -it -v C:\\Users\\USERNAME\\git\\epiphany:/epiphany --rm epiphany-dev - ``` - -- Mounting NTFS disk folders in a linux based image causes permission issues with SSH keys. When running either the development or deploy image: - -1. Copy the certs on the image: - - ```bash - mkdir -p ~/.ssh/epiphany-operations/ - cp /epiphany/core/ssh/id_rsa* ~/.ssh/epiphany-operations/ - ``` -2. Set the propper permission on the certs: - - ```bash - chmod 400 ~/.ssh/epiphany-operations/id_rsa* - ``` - -### Note about proxies - -To run the legacy Epiphany or the new Epicli from behind a proxy, enviroment variables need to be set. - -When running directly from OS (upper and lowercase are needed because of an issue with the Ansible dependency): - - ```bash - export http_proxy="http://PROXY_SERVER:PORT" - export https_proxy="https://PROXY_SERVER:PORT" - export HTTP_PROXY="http://PROXY_SERVER:PORT" - export HTTPS_PROXY="https://PROXY_SERVER:PORT" - ``` - -Or when running from a Docker image (upper and lowercase are needed because of an issue with the Ansible dependency): - - ```bash - docker run -it -v POSSIBLE_MOUNTS... -e HTTP_PROXY=http://PROXY_SERVER:PORT -e HTTPS_PROXY=http://PROXY_SERVER:PORT http_proxy=http://PROXY_SERVER:PORT -e https_proxy=http://PROXY_SERVER:PORT --rm IMAGE_NAME - ``` - -## Import and create of Grafana dashboards - -Epiphany uses Grafana for monitoring data visualization. Epiphany installation creates Prometheus datasource in Grafana, so the only additional step you have to do is to create your dashboard. - -### Creating dashboards - -You can create your own dashboards [Grafana getting started](http://docs.grafana.org/guides/getting_started/) page will help you with it. -Knowledge of Prometheus will be really helpful when creating diagrams since it use [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) to fetch data. - -### Importing dashboards - -There are also many ready to take [Grafana dashboards](https://grafana.com/dashboards) created by community - remember to check license before importing any of those dashboards. -To import existing dashboard: - -1. If you have found dashboard that suits your needs you can import it directly to Grafana going to menu item `Dashboards/Manage` in your Grafana web page. -2. Click `+Import` button. -3. Enter dashboard id or load json file with dashboard definition -4. Select datasource for dashboard - you should select `Prometheus`. -5. Click `Import` - -### How to configure PostgreSQL - -To configure PostgreSQL login to server using ssh and switch to postgres user with command: - -```bash -sudo -u postgres -i -``` - -And then configure database server using psql according to your needs and -PostgreSQL documentation, to which link you can find at - -### How to configure PostgreSQL replication - -In order to configure PostgreSQL replication add to your data.yaml a block similar to the one below to core section: - -```yaml - postgresql: - replication: - enable: yes - user: your-postgresql-replication-user - password: your-postgresql-replication-password - max_wal_senders: 10 # (optional) - default value 5 - wal_keep_segments: 34 # (optional) - default value 32 -``` -If enable is set to yes in replication then Epiphany will automatically create cluster of master and slave server with replication user with name and password -specified in data.yaml. - -### Components used for monitoring - -There are many monitoring components deployed with Epiphany that you can visualize data from. The knowledge which components are used is important when you look for appropriate dashboard on Grafana website or creating your own query to Prometheus. - -List of monitoring components - so called exporters: - -- cAdvisor -- HAProxy Exporter -- JMX Exporter -- Kafka Exporter -- Node Exporter -- Zookeeper Exporter - -When dashboard creation or import succeeds you will see it on your dashboard list. - -## How to configure Kibana - -In order to start viewing and analyzing logs with Kibana, you first need to add an index pattern for Filebeat according to the following steps: - -1. Goto the `Management` tab -2. Select `Index Patterns` -3. On the first step define as index pattern: - `filebeat-*` - Click next. -4. Configure the time filter field if desired by selecting `@timestamp`. This field represents the time that events occurred or were processed. You can choose not to have a time field, but you will not be able to narrow down your data by a time range. - -This filter pattern can now be used to query the Elasticsearch indices. - -By default Kibana adjusts the UTC time in `@timestamp` to the browser's local timezone. This can be changed in `Management` > `Advanced Settings` > `Timezone for date formatting`. - -## How to configure Prometheus alerts - -In order to send messages from Prometheus add monitoring block to your data.yaml similar to the one below: - -```yaml - monitoring: - alerts: - enable: true - handlers: - mail: - smtp_from: 'some-sender@example.com' - smtp_host: 'somesmtp.example.com:587' - smtp_auth_username: 'someusername' - smtp_auth_password: 'somepassword' - smtp_require_tls: true - recipients: ['recipient1@example.com', 'recipient2@example.com'] - rules: - - name: "disk" - expression: ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes) < 99 - duration: 1m #1s, 1m, 1h, 1d, 1w, ... - severity: critical - message: "Disk space Exceeded" - - name: "updown" - expression: up == 0 - duration: 1m #1s, 1m, 1h, 1d, 1w, ... - severity: critical - message: "Instance down" -``` - - monitoring: - this covers whole monitoring section and is needed to define alerts - alerts: - this covers whole alerts section and is needed to define alerts - enable: true - global switch to turn off/on alerts. Set to true enable alerts. - handlers: - this section covers email handlers, right now only email is supported - mail: - global configuration for smtp and email - smtp_from: 'some-sender@example.com' - name of email sender - smtp_host: 'somesmtp.example.com:port' - address of your smtp server with port - smtp_auth_username: 'someusername' - name of your smtp server username - smtp_auth_password: 'somepassword' - password for your smtp server user - smtp_require_tls: true - enabling/disabling tls. Set to true to enable TLS support. - recipients: ['recipient1@example.com', 'recipient2@example.com'] - list of recipients in form - ['recipient1@example.com', 'recipient2@example.com']. At least one recipient has to be declared. - rules: - this section covers rules for Prometheus to enable monitoring. Each of rule have to follow pattern defined below. - - name: "disk" - name of file for Prometheus where rule will be stored. Permitted are alphanumerical characters only. - expression: ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes) < 99 - rule in format of Prometheus queries - duration: 1m #1s, 1m, 1h, 1d, 1w, ... - duration of event after which notification will be sent, follow Prometheus convention - severity: critical - severity label, that will be showed in email sent to users - message: "Disk space Exceeded" - email topic that will be showed in email sent to users - -More information about Prometheus queries you can find under links provided below: - -https://prometheus.io/docs/prometheus/latest/querying/basics/ - -https://prometheus.io/docs/prometheus/latest/querying/examples/ - -Right now we are only supporting email messages, but we are working heavily on introducing integration with Slack and Pager Duty. - -## How to configure scalable Prometheus setup - -If you want to create scalable Prometheus setup you can use federation. Federation lets you scrape metrics from different Prometheus -instances on one Prometheus instance. - -In order to create federation of Prometheus add to your configuration (for example to prometheus.yaml -file) of previously created Prometheus instance (on which you want to scrape data from other -Prometheus instances) to `scrape_configs` section: - -```yaml -scrape_configs: - - job_name: federate - metrics_path: /federate - params: - 'match[]': - - '{job=~".+"}' - honor_labels: true - static_configs: - - targets: - - your-prometheus-endpoint1:9090 - - your-prometheus-endpoint2:9090 - - your-prometheus-endpoint3:9090 - ... - - your-prometheus-endpointn:9090 -``` - -To check if Prometheus from which you want to scrape data is accessible, you can use a command -like below (on Prometheus instance where you want to scrape data): - -`curl -G --data-urlencode 'match[]={job=~".+"}' your-prometheus-endpoint:9090/federate` - -If everything is configured properly and Prometheus instance from which you want to gather data is up -and running, this should return the metrics from that instance. - -## How to configure Azure additional monitoring and alerting - -Setting up addtional monitoring on Azure for redundancy is good practice and might catch issues the Epiphany monitoring might miss like: - -- Azure issues and resource downtime -- Issues with the VM which runs the Epiphany monitoring and Alerting (Prometheus) - -More information about Azure monitoring and alerting you can find under links provided below: - -https://docs.microsoft.com/en-us/azure/azure-monitor/overview - -https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-alerts - -## How to do Kubernetes RBAC - -Kubernetes that comes with Epiphany has an admin account created, you should consider creating more roles and accounts - especially when having many deployments running on different namespaces. - -To know more about RBAC in Kubernetes use this [link](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) - -## How to create an Epiphany cluster on premise - -0. Pull `core` repository and if needed `data` repository (contains data.yaml files that can be used as example or base for creating your own data.yaml). - -1. Prepare your VM/Metal servers: - 1. Install one of supported OS: RedHat 7.4+, Ubuntu 16.04+ - 2. Create user account with sudo privileges and nopasswd that will use rsa key for login. - 3. Assign static IP addresses for each of the machines - those addresses should not change after cluster creation. - 4. Assign hostnames for machines. - 5. Ensure machines have internet access - it will be needed during Epiphany execution. - 6. Machines will strongly utilize communication between each other, so ensure this communication does not go through proxy. - 7. Note down IP addresses and hostnames of your machines. - -2. If you need you can create new directory in `repository_path/data/your_platform/` or you can use existing profile from data repository. Where `your_platform` can be `vmware`, `vbox`, `metal`. -3. Create or modify data.yaml. -4. Fill in data.yaml with hostname information (`nodes[*]/hosts/name`). -5. Fill in data.yaml with IP information (`nodes[*]/hosts/ips/public`). -6. You can adjust roles for each machine - according to your needs (`nodes[*]/ansible_roles`). -7. Run `bash epiphany -a -b -i -p your_platform -f your_profile` in main epiphany directory. Do not use trailing slash after profile name or as prefix to infrastructure. -8. Store artifacts in `/build` directory securely. Keep those files in order to upgrade/scale your cluster. - -## How to create an Epiphany cluster on Azure - -0. Pull core repository and if needed data repository (contains data.yaml files that can be used as example or base for creating your own data.yaml). - -1. If you need you can create new directory in `repository_path/data/azure/infrastructure/` or you can use existing profile from data repository. - -2. Fill/modify content in the `data.yml` file in `repository_path/data/azure/infrastructure/your_profile` according to your needs. Please, make sure you have enough free public ips/cores assigned to your subscription. - - 1. Data.yaml files can be very verbose and at the beginning you can find difficulties modifying it, especially when defining large clusters with many virtual machines. Instead of defining huge data.yaml file - you can use template. - 2. Look at data repository, there is a template for Azure environments in path `repository_path/data/azure/infrastructure/epiphany-template` - 3. Create folder and `basic-data.yaml` file in it (like `/infrastructure/epiphany-rhel-playground/basic-data.yaml`). This file contains basic data for new cluster like subscription, number of VMs, or keys location. - 4. Execute Epiphany engine with following command when using template file: `bash epiphany -a -b -i -f infrastructure/your_profile -t /infrastructure/epiphany-template` - -3. If you executed point 2.4 - skip next step and go to 5. - -4. Run `bash epiphany -a -b -i -f infrastructure/your_profile` in main epiphany directory. Do not use trailing slash after profile name or as prefix to infrastructure. - -5. The first you run the above command line it will prompt you to login to Microsoft and show you something like the following: - - ```text - To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code DBD7WRF3H to authenticate. - ``` - -6. Store artifacts in `/build` directory securely. Keep those files in order to upgrade/scale your cluster. - - Follow the instructions and a token will be generated in your home directory and then a Service Principal will be created and you will not be prompted for this again. - -7. Go to section [Azure post deployment manual steps](#azure-post-deployment-manual-steps) that may be applicable for your deployment. - -## How to create production environment on Azure - -Keep this in mind that Epiphany will create public IPs for each of the machines, you can remove it but running Epiphany again on the same cluster will recreate public IPs. - -There are no manual steps required when you finished with [How to create an Epiphany cluster on Azure](#how-to-create-an-epiphany-cluster-on-azure) until you decide to move to `production environment` where cluster's virtual machines `must not` be exposed to internet (except load balancer - HAProxy role). - -Production environment on cloud should be composed of two elements: - -1. Demilitarized (`DMZ`) group that contains only load balancer (HAProxy role) -2. Applications (`APPS`) group that contains all other roles - -Both elements are deployed independently (for now) that is why some manual steps, that will be described in this chapter, are required. - -### 1. DMZ group - -DMZ group should contain HAProxy role that is used for load balancing and TLS termination. VM that hosts HAProxy should be `the only one` accessible from internet. You can see DMZ implementation with VPN for Epiphany build cluster `repository_path/data/azure/infrastructure/epiphany-bld-dmz`. - -### 2. APPS group - -APPS group contains all features/roles required by your installation - this group should contain (you can enable or disable it) also contain VPN connection so you can access dashboards and logs. You can see APPS group implementation with VPN for Epiphany build cluster `repository_path/data/azure/infrastructure/epiphany-bld-apps`, there is nothing special with this configuration - normal Epiphany data.yaml with VPN enabled (just don't forget to specify you VPN' client certificate). - -When you executed two deployments you should get two resource groups (dmz, apps) with two different VNETs and VPNs. -Now manual steps goes: - -1. Peer you VNET's. Go to VNET setting blade and add peering to another vnet - you have to do it twice, both ways. - -2. Add monitoring endpoints for Prometheus. Load balancer (HAProxy) is separate deployment (for now), but still we have to monitor and take logs from it. That is why we have to add scrape configs for Prometheus (monitoring) - - - SSH into monitoring machine and add `two` files in folder `/etc/prometheus/file_sd/` - - ```yaml - # OS Monitoring - haproxy-vm-node - - targets: ['HAPROXY_MACHINE_PRIVATE_IP:9100'] - labels: - "job": "node" - ``` - - ```yaml - # HAProxy monitoring - haproxy-exporter - - targets: ['HAPROXY_MACHINE_PRIVATE_IP:9101'] - labels: - "job": "haproxy" - ``` - -3. ... and configure address for Elasticsearch (logging) - - - SSH into Load Balancer (HAProxy) machine, and edit file `/etc/filebeat/filebeat.yml`. - - Find `### KIBANA ###` section and add private IP address of Logging VM (`Kibana`) as host value - - Find `### OUTPUTS ###` section and add private IP address of Logging VM (`Elasticsearch`) as host value - -4. For security reasons you should also disassociate public IPs from your APPS virtual machines. - -5. Ensure you defined firewall settings for public VM (load balancer): [How to enable/disable network traffic- firewall](#how-to-enable-disable-network-traffic) - -## How to run an example app - -Here we will get a simple app to run using Docker through Kubernetes. We assume you are using Windows 10, have an Epiphany cluster on Azure ready and have an Azure Container Registry ready (might not be created in early version Epiphany clusters - if you don't have one you can skip to point no 11 and test the cluster using some public app from the original Docker Registry). Steps with asterisk can be skipped. - -1. Install [Chocolatey](https://chocolatey.org/install) - -2. Use Chocolatey to install: - - - Docker-for-windows (`choco install docker-for-windows`, requires Hyper-V) - - Azure-cli (`choco install azure-cli`) - -3. Make sure Docker for Windows is running (run as admin, might require a restart) - -4. Run `docker build -t sample-app:v1 .` in examples/dotnet/epiphany-web-app. - -5. *For test purposes, run your image locally with `docker run -d -p 8080:80 --name myapp sample-app:v1` and head to `localhost:8080` to check if it's working. - -6. *Stop your local docker container with: `docker stop myapp` and run `docker rm myapp` to delete the container. - -7. *Now that you have a working docker image we can proceed to the deployment of the app on the Epiphany Kubernetes cluster. - -8. Run `docker login myregistry.azurecr.io -u myUsername -p myPassword` to login into your Azure Container Registry. Credentials are in the `Access keys` tab in your registry. - -9. Tag your image with: `docker tag sample-app:v1 myregistry.azurecr.io/samples/sample-app:v1` - -10. Push your image to the repo: `docker push myregistry.azurecr.io/samples/sample-app:v1` - -11. SSH into your Epiphany clusters master node. - -12. *Run `kubectl cluster-info` and `kubectl config view` to check if everything is okay. - -13. Run `kubectl create secret docker-registry myregistry --docker-server myregistry.azurecr.io --docker-username myusername --docker-password mypassword` to create k8s secret with your registry data. - -14. Create `sample-app.yaml` file with contents: - - ```yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - name: sample-app - spec: - selector: - matchLabels: - app: sample-app - replicas: 2 - template: - metadata: - labels: - app: sample-app - spec: - containers: - - name: sample-app - image: myregistry.azurecr.io/samples/sample-app:v1 - ports: - - containerPort: 80 - resources: - requests: - cpu: 100m - memory: 64Mi - limits: - memory: 128Mi - imagePullSecrets: - - name: myregistry - ``` - -15. Run `kubectl apply -f sample-app.yaml`, and after a minute run `kubectl get pods` to see if it works. - -16. Run `kubectl expose deployment sample-app --type=NodePort --name=sample-app-nodeport`, then run `kubectl get svc sample-app-nodeport` and note the second port. - -17. Run `kubectl get pods -o wide` and check on which node is the app running. - -18. Access the app through [AZURE_NODE_VM_IP]:[PORT] from the two previous points - firewall changes might be needed. - -## How to set resource requests and limits for Containers - -When Kubernetes schedules a Pod, it’s important that the Containers have enough resources to actually run. If you schedule a large application on a node with limited resources, it is possible for the node to run out of memory or CPU resources and for things to stop working! It’s also possible for applications to take up more resources than they should. - -When you specify a Pod, it is strongly recommended to specify how much CPU and memory (RAM) each Container needs. Requests are what the Container is guaranteed to get. If a Container requests a resource, Kubernetes will only schedule it on a node that can give it that resource. Limits make sure a Container never goes above a certain value. For more details about the difference between requests and limits, see [Resource QoS](https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md). - -For more information, see the links below: - -- [Kubernetes best practices: Resource requests and limits](https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits) -- [Managing Compute Resources for Containers](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) - -## How to run CronJobs - -1. Follow the previous point using examples/dotnet/Epiaphany.SampleApps/Epiphany.SampleApps.CronApp - -2. Create `cronjob.yaml` file with contents: - - ```yaml - apiVersion: batch/v1beta1 - kind: CronJob - metadata: - name: sample-cron-job - spec: - schedule: "*/1 * * * *" # Run once a minute - failedJobsHistoryLimit: 5 - jobTemplate: - spec: - template: - spec: - containers: - - name: sample-cron-job - image: myregistry.azurecr.io/samples/sample-cron-app:v1 - restartPolicy: OnFailure - imagePullSecrets: - - name: myregistrysecret - ``` - -3. Run `kubectl apply -f cronjob.yaml`, and after a minute run `kubectl get pods` to see if it works. - -4. Run `kubectl get cronjob sample-cron-job` to get status of our cron job. - -5. Run `kubectl get jobs --watch` to see job scheduled by the “sample-cron-job” cron job. - -## How to test the monitoring features - -Prerequisites: Epiphany cluster on Azure with at least a single VM with `prometheus` and `grafana` roles enabled. - -1. Copy ansible inventory from `build/epiphany/*/inventory/` to `examples/monitoring/` - -2. Run `ansible-playbook -i NAME_OF_THE_INVENTORY_FILE grafana.yml` in `examples/monitoring` - -3. In the inventory file find the IP adress of the node of the machine that has grafana installed and head over to `https://NODE_IP:3000` - you might have to head over to Portal Azure and allow traffic to that port in the firewall, also ignore the possible certificate error in your browser. - -4. Head to `Dashboards/Manage` on the side panel and select `Kubernetes Deployment metrics` - here you can see a sample kubernetes monitoring dashboard. - -5. Head to `http://NODE_IP:9090` to see Prometheus UI - there in the dropdown you have all of the metrics you can monitor with Prometheus/Grafana. - -## How to run chaos on Epiphany Kubernetes cluster and monitor it with Grafana - -1. SSH into the Kubernetes master. - -2. Copy over `chaos-sample.yaml` file from the example folder and run it with `kubectl apply -f chaos-sample.yaml` - it takes code from `github.com/linki/chaoskube` so normal security concerns apply. - -3. Run `kubectl create clusterrolebinding chaos --clusterrole=cluster-admin --user=system:serviceaccount:default:default` to start the chaos - random pods will be terminated with 5s ferquency, configurable inside the yaml file. - -4. Head over to Grafana at `https://NODE_IP:3000`, open a new dashboard, add a panel, set Prometheus as a data source and put `kubelet_running_pod_count` in the query field - now you can see how Kubernetes is replacing killed pods and balancing them between the nodes. - -5. Run `kubectl get svc nginx-service` and note the second port. You can access the nginx page via `[ANY_CLUSTER_VM_IP]:[PORT]` - it is accessible even though random pods carrying it are constantly killed at random, unless you have more vms in your cluster than deployed nginx instances and choose IP of one not carrying it. - -## How to test the central logging features - -Prerequisites: Epiphany cluster on Azure with at least a single VM with `elasticsearch`, `kibana` and `filebeat` roles enabled. - -1. Connect to kubectl using kubectl proxy or directly from Kubernetes master server - -2. Apply from epiphany repository `extras/kubernetes/pod-counter` `pod-counter.yaml` with command: `kubectl apply -f yourpath_to_pod_counter/pod-counter.yaml` - - Paths are system dependend so please be aware of applying correct separator for your operatins system. - -3. In the inventory file find the IP adress of the node of the machine that has kibana installed and head over to `http://NODE_IP:5601` - you might have to head over to Portal Azure and allow traffic to that port in the firewall. - -4. You can right now search for data from logs in Discover section in Kibana after creating filebeat-* index pattern. To create index pattern click Discover, then in Step 1: Define index pattern as filebeat-*. Then click Next step. In Step 2: Configure settings click Create index pattern. Right now you can go to Discover section and look at output from your logs. - -5. You can verify if CounterPod is sending messages correctly and filebeat is gathering them correctly querying for `CounterPod` in search field in Discover section. - -6. For more informations refer to documentation: - -## How to tunnel kubernetes dashboard from remote kubectl to your PC - -1. SSH into server, and forward port 8001 to your machine `ssh -i epi_keys/id_rsa operations@40.67.255.155 -L 8001:localhost:8001` NOTE: substitute IP with your cluster master's IP. - -2. On **remote** host: get admin token bearer: `kubectl describe secret $(kubectl get secrets --namespace=kube-system | grep admin-user | awk '{print $1}') --namespace=kube-system | grep -E '^token' | awk '{print $2}' | head -1` NOTE: save this token for next points. - -3. On **remote** host, open proxy to the dashboard `kubectl proxy` - -4. Now on your **local** machine navigate to `http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/overview?namespace=default` - -5. When prompted to put in credentials, use admin token from the previous point. - -## How to setup Azure VM as docker machine for development - -0. Make sure you have docker-machine installed `(choco install docker-machine)` - -1. Run the following: - - ```bash - docker-machine create --driver azure --azure-subscription-id --azure-resource-group --azure-vnet --azure-subnet default --azure-location westeurope - ``` - -2. When the creation succeedes go ahead and connect to your docker-machine using `docker-machine env ` and later invoke commands as instructed by docker-machine - -3. Check if everything is working with `docker run hello-world` - -Now your docker containers are running on a separate system without you having to worry about overhead. -Source: - -## How to use Kubernetes Secrets - -Prerequisites: Epiphany Kubernetes cluster - -1. SSH into the Kubernetes master. - -2. Run `echo -n 'admin' > ./username.txt`, `echo -n 'VeryStrongPassword!!1' > ./password.txt` and `kubectl create secret generic mysecret --from-file=./username.txt --from-file=./password.txt` - -3. Copy over `secrets-sample.yaml` file from the example folder and run it with `kubectl apply -f secrets-sample.yaml` - -4. Run `kubectl get pods`, copy the name of one of the ubuntu pods and run `kubectl exec -it POD_NAME -- /bin/bash` with it. - -5. In the pods bash run `printenv | grep SECRET` - Kubernetes secret created in point 2 was attached to pods during creation (take a look at `secrets-sample.yaml`) and are availiable inside of them as an environmental variables. - -## How to authenticate to Azure AD app - -1. Register you application. Go to Azure portal to `Azure Active Directory => App registrations` tab. - -2. Click button `New application registration` fill the data and confirm. - -3. Deploy app from `examples/dotnet/Epiphany.SampleApps/Epiphany.SampleApps.AuthService`. - - This is a test service for verification Azure AD authentication of registered app. ([How to deploy app](#how-to-run-an-example-app)) - -4. Create secret key for your app `settings => keys`. Remember to copy value of key after creation. - -5. Try to authenticate (e.g. using postman) calling service api `/api/auth/` with following Body application/json type parameters : - - ```json - { - "TenantId": "", - "ClientId": "", - "Resource": "https://graph.windows.net/", - "ClientSecret": "" - } - ``` - - - TenantId - Directory ID, which you find in `Azure active Directory => Properties` tab. - - - ClientId - Application ID, which you find in details of previously registered app `Azure Active Directory => App registrations => your app` - - - Resource - is the service root of Azure AD Graph API. The Azure Active Directory (AD) Graph API provides programmatic access to Azure AD through OData REST API endpoints. You can construct your own Graph API URL. ([How to construct a Graph API URL](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api-quickstart)) - - - ClientSecret - Created secret key from 4. point. - -6. The service should return Access Token. - -## How to expose service through HA Proxy load balancer - -1. Add haproxy role to your data.yaml -2. Create a folder repository_path/core/src/ansible/roles/haproxy/vars/ -3. Create a file repository_path/core/src/ansible/roles/haproxy/vars/main.yml: -4. Add to repository_path/core/src/ansible/roles/haproxy/vars/main.yml content: - - ```yaml - --- - service_port: your_service_port - ``` - - Where `your_service_port` is a port where your service is exposed using NodePort. - -## How to set HA Proxy load balancer to minimize risk of Slowloris like attacks - -1. Add haproxy_tls_termination role to your data.yaml -2. If you want to minimize risk of Slowloris like attacks add to your data.yaml in section for haproxy: - - ```yaml - haproxy: - http_request_timeout: 5s - ``` - - Where http_request_timeout is the number_of_seconds with s after which connection to HAProxy will be terminated by HAProxy. - This parameter is optional, if is not present no timeout http-request in global section of HAProxy configuration will be set. - -## How to use TLS/SSL certificate with HA Proxy - -If you want to use HAProxy with TLS/SSL certificate follow the instruction below. - -1. Add haproxy_tls_termination role to your data.yaml -2. If you want to use your certificates, you can add to section core to your data.yaml: - - ```yaml - haproxy: - haproxy_certs_dir: your_path_to_certificates - ``` - - Your certificates will be copied and applied automatically to HA Proxy configuration. - - Please be aware that `your_path_to_certificates` cannot contain variables (`$HOME`) or tilde (`~`) as this will make deployment of Epiphany fail. Additionally if you need more than one DNS name for your frontend you need to provide certificates on your own, as there is only one self-signed certificate generated by this role with CN localhost. For multiple backends you need to provide also mapping as described in later part of this document. - -3. If you don't want to apply your certificates that will be generated automatically, then just don't put any certificate in `your_path_to_certificates` or don't put section with `haproxy: haproxy_certs_dir` in your data.yaml - -4. Below you can find example of configuration: - ```yaml - haproxy: - haproxy_certs_dir: /home/epiphany/certs/ - frontend: - - name: https_front - port: 443 - https: yes - backend: - - http_back1 - - http_back2 - domain_backend_mapping: - - domain: backend1.domain.com - backend: http_back1 - - domain: backend2.domain.com - backend: http_back2 - - name: http_front1 - port: 80 - https: no - backend: - - http_back2 - - name: http_front2 - port: 8080 - https: no - backend: - - http_back1 - - http_back2 - domain_backend_mapping: - - domain: http-backend1.domain.com - backend: http_back1 - - domain: http-backend2.domain.com - backend: http_back2 - backend: - - name: http_back1 - server_groups: - - worker - port: 30001 - - name: http_back2 - server_groups: - - worker - - kibana - port: 30002 - ``` - -5. Parameters description: - - `haproxy_certs_dir` - (Optional) Path on machine from which you run Epiphany installer where certificates generated by you are stored. If not one certificate with CN localhost will be generated, works only with one frontend definition, in other cases it won't be able to redirect you to correct backend on HAProxy. - - `frontend` - (Mandatory) At least one frontend configuration must exist, if more than one domain must be supported than `domain_backend_mapping` section is mandatory, as this will make fail. This is a list of frontend, each position has to start with `-`. - - - `name` - (Mandatory) Name of each configuration for frontend. - - `port` - (Mandatory) Port to which frontend should be binding. Must be unique for all frontends in other case it will make HAProxy fail. - - `https` - (Mandatory) Information if https will be used - options `yes`/`no`. If `no`, only http part of configuration for frontend will be generated. - - `backend` - (Mandatory) At least one backend configuration must exist. If `domain_backend_mapping` exists this must match configuration in `domain_backend_mapping` backend section. It always has to match configuration from backend name section. This is a list of backend, each position has to start with `-`. This parameter shows to which backend configuration forward traffic from frontend to backend. - - - `domain_backend_mapping` - (Optional) If this exist at least one domain to backend mapping must exist. Must be provided if more than one domain has to be supported. - - - `domain` - (Mandatory if `domain_backend_mapping` used for each mapping) Domain that matches SSL certificate CN for https configuration and domain name. For http, domain that will be mapped using http header. - - `backend` - (Mandatory if `domain_backend_mapping` used for each mapping) Must match name from backend section - - `backend` - (Mandatory) This is a list of backend, each position has to start with `-`. At least one backend used by frontend must exist. If there won't be a match with each frontend configuration HAProxy will fail to start. - - `name` - (Mandatory) Name of each configuration for backend, must match frontend backend configuration and `domain_backend_mapping` backend part in frontend section. - - `server_groups` - (Mandatory) This is a list of server groups, each position has to start with `-`. At least one `server_group` used by backend must exist. It must match Epiphany role e.g. `kibana`, `worker` etc. - - `port` - (Mandatory) Port on which backend service is exposed. - -## How to upgrade Kubernetes cluster - -Upgrade procedure might be different for each Kubernetes version. Upgrade shall be done only from one minor version to next minor version. For example, upgrade from 1.9 to 1.11 looks like this: - -```text -1.9.x -> 1.9.y -1.9.y -> 1.10 -1.10 -> 1.11 -``` - -Each version can be upgraded in a bit different way, to find information how to upgrade your version of Kubernetes please use this [guide](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-upgrade/#kubeadm-upgrade-guidance). - -Epiphany uses kubeadm to boostrap a cluster and the same tool is also used to upgrade it. - -Upgrading Kubernetes cluster with running applications shall be done step by step. To prevent your applications downtime you should use at least **two Kubernetes worker nodes** and at least **two instances of each of your service**. - -Start cluster upgrade with upgrading master node. Detailed instructions how to upgrade each node, including master, are described in guide linked above. When Kubernetes master is down it does not affect running applications, at this time only control plane is not operating. **Your services will be running but will not be recreated nor scaled when control plane is down.** - -Once master upgrade finished successfully, you shall start upgrading nodes - **one by one**. Kubernetes master will notice when worker node is down and it will instatiate services on existing operating node, that is why it is essential to have more than one worker node in cluster to minimize applications downtime. - -## How to upgrade Kubernetes cluster from 1.13.0 to 1.13.1 - -Detailed instruction can be found in [Kubernetes upgrade to 1.13 documentation](https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-13/) - -### Ubuntu Server - -#### Upgrade Master - -```bash -# RUN ON MASTER - -1. sudo kubeadm version # should show v1.13.0 -2. sudo kubeadm upgrade plan v1.13.1 - -3. apt update -4. apt-cache policy kubeadm - - -5. sudo apt-mark unhold kubeadm && \ -sudo apt-get update && sudo apt-get install -y kubeadm=1.13.1-00 && \ -sudo apt-mark hold kubeadm - -6. sudo kubeadm version # should show v1.13.1 -7. sudo kubeadm upgrade plan v1.13.1 - -8. sudo kubeadm upgrade apply v1.13.1 - -9. sudo apt-mark unhold kubelet && \ -sudo apt-get update && sudo apt-get install -y kubelet=1.13.1-00 && \ -sudo apt-mark hold kubelet -``` - -#### Upgrade Worker Nodes - -Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) - -Worker nodes will be upgraded one by one - it will prevent application downtime. - -```bash - -# RUN ON WORKER NODE - $NODE - -1. sudo apt-mark unhold kubectl && \ -sudo apt-get update && sudo apt-get install -y kubectl=1.13.1-00 && \ -sudo apt-mark hold kubectl - -# RUN ON MASTER - -2. kubectl drain $NODE --ignore-daemonsets - -# RUN ON WORKER NODE - $NODE - -3. sudo kubeadm upgrade node config --kubelet-version v1.13.1 - -4. sudo apt-get update -5. sudo apt-get install -y kubelet=1.13.1-00 kubeadm=1.13.1-00 - -6. sudo systemctl restart kubelet -7. sudo systemctl status kubelet # should be running - -# RUN ON MASTER - -8. kubectl uncordon $NODE - -9. # go to 1. for next node - -# RUN ON MASTER -10. kubectl get nodes # should return nodes in status "Ready" and version 1.13.1 - -``` - -### RHEL - -#### Upgrade Docker version - -Upgrading Kubernetes to 1.13.1 on RHEL requires Docker upgrade. Newer Docker packages exist in docker-ce repository but you can use newer Docker-ee if you need. Verified Docker versions for Kubernetes are: 1.11.1, 1.12.1, 1.13.1, 17.03, 17.06, 17.09, 18.06. [Go to K8s docs](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.13.md#external-dependencies) - -```bash - -# Remove previous docker version -1 sudo yum remove docker \ - docker-common \ - container-selinux \ - docker-selinux \ - docker-engine -2. sudo rm -rf /var/lib/docker -3. sudo rm -rf /run/docker -4. sudo rm -rf /var/run/docker -5. sudo rm -rf /etc/docker - -# Add docker-ce repository -6. sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo -7. sudo yum makecache fast -8. sudo yum -y install docker-ce-18.06.3.ce-3.el7 - -``` - -#### Upgrade Master - -```bash -# RUN ON MASTER - -1. sudo kubeadm version # should show v1.13.0 -2. sudo kubeadm upgrade plan v1.13.1 - -3. sudo yum install -y kubeadm-1.13.1-0 --disableexcludes=kubernetes - -4. sudo kubeadm version # should show v1.13.1 -5. sudo kubeadm upgrade plan v1.13.1 - -6. sudo kubeadm upgrade apply v1.13.1 - -7. sudo yum install -y kubelet-1.13.1-0 --disableexcludes=kubernetes - -``` - -#### Upgrade Worker Nodes - -Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) - -Worker nodes will be upgraded one by one - it will prevent application downtime. - -```bash - -# RUN ON WORKER NODE - $NODE - -1. yum install -y kubectl-1.13.1-0 --disableexcludes=kubernetes - -# RUN ON MASTER - -2. kubectl drain $NODE --ignore-daemonsets - -# RUN ON WORKER NODE - $NODE - -3. # Upgrade Docker version using instruction from above - -4. sudo kubeadm upgrade node config --kubelet-version v1.13.1 - -5. sudo yum install -y kubelet-1.13.1-0 kubeadm-1.13.1-0 --disableexcludes=kubernetes - -6. sudo systemctl restart kubelet -7. sudo systemctl status kubelet # should be running - -# RUN ON MASTER - -8. kubectl uncordon $NODE - -9. # go to 1. for next node - -# RUN ON MASTER -10. kubectl get nodes # should return nodes in status "Ready" and version 1.13.1 - -``` - -## How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch - -### Ubuntu Server - -#### Upgrade Master - -Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) - -##### > RUN ON MASTER - -1. Check kubeadm version -```bash -kubeadm version -# should show v1.13.1 -``` -2. Find the latest stable 1.13 version -```bash -sudo apt update -apt-cache policy kubeadm -# 1.13.10-0 -``` -3. Drain master in preparation for maintenance -```bash -kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] -# $MASTER should be marked as Ready,SchedulingDisabled -``` -may need to use flags: -```bash ---ignore-daemonsets: # to ignore DaemonSet-managed pods - ---delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) -# BE CAREFUL! -``` -4. Wait for all pods to be running and ready - -5. Install packages -```bash -sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ -sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ -sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm -``` -6. Validate whether current cluster is upgradeable -```bash -sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] -``` -7. Upgrade Kubernetes cluster to the specified version -```bash -sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] -``` -8. Wait for all pods to be running and ready - -9. Reload daemon -```bash -sudo systemctl daemon-reload -``` -10. Restart kubelet -```bash -sudo systemctl restart kubelet -``` -11. Check kubelet status -```bash -sudo systemctl status kubelet -# should be active (running) -``` -12. Wait for cluster to be ready, e.g. check: -```bash -kubectl cluster-info -``` -13. Uncordon master - mark as schedulable -```bash -kubectl uncordon $MASTER -``` -14. List all nodes -```bash -kubectl get nodes -# should return $MASTER in status "Ready" and version 1.13.10 -``` - -#### Upgrade Worker Nodes - -Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) - -Important: Worker nodes should be upgraded one by one - this will prevent application downtime. - -##### > RUN ON MASTER - -1. Drain node in preparation for maintenance -```bash -kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] -# $NODE should be marked as Ready,SchedulingDisabled -``` -may need to use flags: -```bash ---ignore-daemonsets: # to ignore DaemonSet-managed pods - ---delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) -# BE CAREFUL! -``` -2. Wait for all pods to be running and ready - -##### > RUN ON NODE - -3. Install packages -```bash -sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ -sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ -sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm -``` -4. Upgrade node config -```bash -sudo kubeadm upgrade node config --kubelet-version v1.13.10 -``` -5. Reload daemon -```bash -sudo systemctl daemon-reload -``` -6. Restart kubelet -```bash -sudo systemctl restart kubelet -``` -7. Check kubelet status -```bash -sudo systemctl status kubelet -# should be active (running) -``` -##### > RUN ON MASTER - -8. Uncordon node - mark as schedulable -```bash -kubectl uncordon $NODE -``` -9. List all nodes -```bash -kubectl get nodes -# should return $NODE in status "Ready" and version 1.13.10 -``` -10. Go back to the point 1 with the next node - - -### RHEL - -#### Upgrade Master - -Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) - -##### > RUN ON MASTER - -1. Check kubeadm version -```bash -kubeadm version -# should show v1.13.1 -``` -2. Find the latest stable 1.13 version -```bash -yum list --showduplicates kubeadm --disableexcludes=kubernetes -# 1.13.10-0 -``` -3. Drain master in preparation for maintenance -```bash -kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] -# $MASTER should be marked as Ready,SchedulingDisabled -``` -may need to use flags: -```bash ---ignore-daemonsets: # to ignore DaemonSet-managed pods - ---delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) -# BE CAREFUL! -``` -4. Wait for all pods to be running and ready - -5. Install packages -```bash -sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes -``` -6. Validate whether current cluster is upgradeable -```bash -sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] -``` -7. Upgrade Kubernetes cluster to the specified version -```bash -sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] -``` -8. Wait for all pods to be running and ready - -9. Reload daemon -```bash -sudo systemctl daemon-reload -``` -10. Restart kubelet -```bash -sudo systemctl restart kubelet -``` -11. Check kubelet status -```bash -sudo systemctl status kubelet -# should be active (running) -``` -12. Wait for cluster to be ready, e.g. check: -```bash -kubectl cluster-info -``` -13. Uncordon master - mark as schedulable -```bash -kubectl uncordon $MASTER -``` -14. List all nodes -```bash -kubectl get nodes -# should return $MASTER in status "Ready" and version 1.13.10 -``` - -#### Upgrade Worker Nodes - -Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) - -Important: Worker nodes should be upgraded one by one - this will prevent application downtime. - -##### > RUN ON MASTER - -1. Drain node in preparation for maintenance -```bash -kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] -# $NODE should be marked as Ready,SchedulingDisabled -``` -may need to use flags: -```bash ---ignore-daemonsets: # to ignore DaemonSet-managed pods - ---delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) -# BE CAREFUL! -``` -2. Wait for all pods to be running and ready - -##### > RUN ON NODE - -3. Install packages -```bash -sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes -``` -4. Upgrade node config -```bash -sudo kubeadm upgrade node config --kubelet-version v1.13.10 -``` -5. Reload daemon -```bash -sudo systemctl daemon-reload -``` -6. Restart kubelet -```bash -sudo systemctl restart kubelet -``` -7. Check kubelet status -```bash -sudo systemctl status kubelet -# should be active (running) -``` -##### > RUN ON MASTER - -8. Uncordon node - mark as schedulable -```bash -kubectl uncordon $NODE -``` -9. List all nodes -```bash -kubectl get nodes -# should return $NODE in status "Ready" and version 1.13.10 -``` -10. Go back to the point 1 with the next node - -## How to upgrade Kafka cluster - -### Kafka upgrade - -No downtime upgrades are possible to achieve when upgrading Kafka, but before you start thinking about upgrading you have to think about your topics configuration. Kafka topics are distributed accross partitions with replication. Default value for replication is 3, it means each partition will be replicated to 3 brokers. You should remember to enable redundancy and keep **at least two replicas all the time**, it is important when upgrading Kafka cluser. When one of your Kafka nodes will be down during upgrade ZooKeeper will direct your producers and consumers to working instances - having replicated partitions on working nodes will ensure no downtime and no data loss work. - -Upgrading Kafka could be different for every Kafka release, please refer to [Apache Kafka documentation](https://kafka.apache.org/documentation/#upgrade). Important point to remember during Kafka upgrade is the rule: **only one broker at the time** - to prevent downtime you should uprage you Kafka brokers one by one. - -### ZooKeeper upgrade - -ZooKeeper redundancy is also recommended, since service restart is required during upgrade - it can cause ZooKeeper unavailability. Having at **least two ZooKeeper services** in *ZooKeepers ensemble* you can upgrade one and then start with the rest **one by one**. - -More detailed information about ZooKeeper you can find in [ZooKeeper documentation](https://cwiki.apache.org/confluence/display/ZOOKEEPER). - -## How to enable or disable network traffic - -### VM Firewall - -Epiphany 1.0 supports firewalld on host machines (RedHat only). You can enable firewall setting `.../security/firewall/enable` to `true` in data.yaml. Remember to allow port 22 to be open in ports_open (`.../security/firewall/ports_open`) dictionary in order to configuration can do its job. - -### Azure specific - Network Security Group - -Security for internet facing infrastructure is extremely important thing - remember to configure `Network Security Group` rules to allow network traffic only on required ports and directions. You can do it using Azure specific data.yaml in section `.../network_security_group/rules`. Remember to allow port 22 (you can/should remove this rule after deployment) in order to configuration can do its job. - -## Client certificate for Azure VPN connection - -Epiphany will create point to site configuration (if you enable VPN in `.../security/vpn/enable` and specify public key of your certificate, in base64 format, in `public_cert_data` field). For production environments you have to use root certificate from `trusted provider`. -For development purposes you can use self signed certificate which can be generated using powershell: - -When you get root certificate you should generate child certificate(s) that will be distributed to the team that should have VPN access to clusters. -Configuration of client config in data.yaml (`.../security/vpn/client_configuration/root_certificate`) looks like following: - -```yaml -... -root_certificate: - # name is the name of the cert that was created for you by a trusted party OR a name you give a self-signed cert - name: NAME-OF-YOUR-CERTIFICATE - revoked_certificate: - name: NAME-OF-REVOKED-CERTIFICATE - thumbprint: THUMBPRINT-OF-REVOKED-CERTIFICATE - # public_cert_data is the actual base64 public key from your cert. Put it in 'as is'. The '|' tells yaml to use 'as is'. - public_cert_data: | - YOUR-BASE64-CLIENT-AUTH-PUBLIC-KEY -... -``` - -Configuration requires to have revoked certificate filled in (for now). - -## How to enable AWS disk encryption - -### EC2 Root volumes - -Since [May 2019](https://aws.amazon.com/about-aws/whats-new/2019/05/launch-encrypted-ebs-backed-ec2-instances-from-unencrypted-amis-in-a-single-step/) AWS supports the creation of instances from unencrypted AMIs. At this point Terraform does not [support](https://github.com/terraform-providers/terraform-provider-aws/issues/8624) this jet. If you need encrypted root volumes for now you need to supply your own pre-encryped AMIs as specified in the guide [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html). - -We will add this as the functionality becomes available in Terraform. The issue is beeing tracked [here](https://github.com/epiphany-platform/epiphany/issues/381). - -### Additional EC2 storage - -When defining extra storage inside the `infrastructure/virtual-machine` document one can set the `encryption` flag: - -```yaml -... -additional_disks: - - device_name: "/dev/sdb" - volume_type: gp2 - volume_size: 60 - delete_on_termination: true - encrypted: true -... -``` - -### EFS storage - -EFS storage is encrypted by default. - -## Build artifacts - -Epiphany engine produce build artifacts during each deployment. Those artifacts contains: - -- Generated terraform files. -- Generated terraform state files. -- Generated cluster manifest file. -- Generated ansible files. -- Azure login credentials for `service principal` if deploying to Azure. - -Artifacts contains sensitive data so it is important to keep it in safe place like `private GIT repository` or `storage with limited access`. Generated build is also important in case of scaling or updating cluster - you will it in build folder in order to edit your cluster. - -Epiphany creates (or use if you don't specified it to create) service principal account which can manage all resources in subscription, please store build artifacts securely. - -## How to scale Kubernetes and Kafka - -### Scaling Kubernetes - -For Azure specific deployment configuration for Kubernetes Node looks like that: - -```yaml -vms: - - name: vm-k8s-node - size: Standard_DS1_v2 - os_type: linux - count: 1 - bastian_host: false - # roles are how you define a grouping of nodes. These values will be used to create an inventory of your cluster - # Must be a member of the 'role' in core - roles: - - linux - - worker - - node_exporter - - filebeat - - reboot -``` - -There is 1 worker role defined - it means only one Kubernetes node virtual machine will be created and configured to join Kubernetes cluster. When Epiphany deployment was created with one Kubernetes node and then you decide to have more nodes you can simply change - -```yaml -count: 1 -``` - -to - -```yaml -count: 2 -``` - -and wait for add new node. It is important to have your build folder from initial deployment so now state will be automatically refreshed with no downtime. For more information about build folder go to [Build artifacts](#build-artifacts) section. - -For all other deployments (Metal, VMWare, VirtualBox, etc.) you just have to add another definition for machine with worker role. - -### Scaling Kafka - -Scaling Kafka looks exactly the same like scaling Kubernetes. Once changed `count:` property from `1` to `n` and executed Epiphany you will have `n` Kafka machines. - -To add new Kafka broker to non-Azure deployment looks the same as adding new Kubernetes node. - -## Kafka replication and partition setting - -When planning Kafka installation you have to think about number of partitions and replicas since it is strongly related to throughput of Kafka and its reliability. By default Kafka's `replicas` number is set to 1 - you should change it in `core/src/ansible/roles/kafka/defaults` in order to have partitions replicated to many virtual machines. - -```yaml - ... - replicas: 1 # Default to at least 1 (1 broker) - partitions: 8 # 100 x brokers x replicas for reasonable size cluster. Small clusters can be less - ... -``` - -You can read more [here](https://www.confluent.io/blog/how-choose-number-topics-partitions-kafka-cluster) about planning number of partitions. - -## RabbitMQ installation and setting - -To install RabbitMQ in single mode just add rabbitmq role to your data.yaml for your sever and in general roles section. All configuration on RabbitMQ - e.g. user other than guest creation should be performed manually. - -## Single machine cluster - -In certain circumstances it might be desired to run an Epiphany cluster on a single machine. There are 2 example data.yamls provided for baremetal and Azure: - -- `/core/data/metal/epiphany-single-machine/data.yaml` -- `/core/data/azure/infrastructure/epiphany-single-machine/data.yaml` - -These will install the following minimal set of components on the machine: - -- kubernetes master (Untainted so it can run and manage deployments) -- node_exporter -- prometheus -- grafana -- rabbitmq -- postgresql (for keycloak) -- keycloak (2 instances) - -This bare installation will consume arround 2.8Gb of memory with the following base memory usage of the different components: - -- kubernetes : 904 MiB -- node_exporter : 38 MiB -- prometheus : 133 MiB -- grafana : 54 MiB -- rabbitmq : 85 MiB -- postgresql : 35 MiB -- keycloak : 1 Gb - -Additional resource consumption will be highly dependant on how the cluster is utilized and it will be up to the product teams to define there hardware requirements. The absolute bare minimum this cluster was tested on was a quadcore CPU with 8Gb of ram and 60Gb of storage. However a minimum of an 8 core CPU with 16Gb of ram and 100Gb of storage would be recommended. - -## Data and log retention - -An Epiphany cluster has a number of components which log, collect and retain data. To make sure that these do not exceed the usable storage of the machines there running on the following configurations are available. - -### Elasticsearch - -For managing the data storage that Elasticsearch consumes we use [Elasticsearch Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html). To use it one needs to make sure the elasticsearch-curator is enabled. This role will install and configure the [Elasticsearch Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html) to run in a cronjob to clean up older indices which are older then a certain treshold. - -In the default configuration `/core/src/ansible/roles/elasticsearch-curator/defaults/main.yml` the following values can be tweaked regarding storage: - -```yaml -# Rentention time of Elasticsearch indices in days. -indices_retention_days: 30 -``` - -The size of the storage consumed by Elasticsearch is depenedant on the clustersize and how much logging the deployed application will generate. - -### Grafana - -In the default configuration `/core/src/ansible/roles/grafana/defaults/main.yml` the following values can be tweaked to control the ammount of storage used by Grafana: - -```yaml -# The path where Grafana stores its logs -grafana_logs_dir: "/var/log/grafana" - -# The path where Grafana stores it's (Dashboards DB (SQLLite), sessions, etc) -grafana_data_dir: "/var/lib/grafana" - -grafana_logging: -# Enable or disable log rotation -log_rotate: true - -# Enable or disable daily log rotation -daily_rotate: true - -# Number of days to retain the logs -max_days: 7 -``` - -While logs can be rotated and have a retention time, the ammount of storage used by Grafana is dependant on user usage and dashboard count and cannot be directly controlled. - -### Kafka - -In the default configuration `/core/src/ansible/roles/kafka/defaults/main.yml` the following values can be tweaked regarding storage: - -```yaml -# The path where kafka stores its data -data_dir: /var/lib/kafka - -# The path where kafka stores its logs -log_dir: /var/log/kafka - -# The minimum age of a log file to be eligible for deletion due to age -log_retention_hours: 168 - -# Offsets older than this retention period will be discarded -offset_retention_minutes: 10080 -``` - -The ammount of storage Kafka consumes is dependant on the application running on Epiphany, how many messages producers create and how fast the consumers can consume them. It's up to the application developer to configure a `log_retention_hours` and `offset_retention_minutes` to suite the applications need. - -Since Kafka does not have a mechanism for log rotation we use [logrotate](https://linux.die.net/man/8/logrotate) for this. The template for logrotate can be found here: - -`/core/src/ansible/roles/kafka/templates/logrotate.conf.j2` - -On the system the configuration can be found here: - -`/etc/logrotate.d/kafka` - -### Kibana - -In the default configuration `/core/src/ansible/roles/kibana/defaults/main.yml` the following values can be tweaked regarding storage: - -```yaml -# The path where Kibana stores its logs -kibana_log_dir: /var/log/kibana -``` - -Since Kibana does not have a mechanism for log rotation we use [logrotate](https://linux.die.net/man/8/logrotate) for this. The template for logrotate can be found here: - -`/core/src/ansible/roles/kibana/templates/logrotate.conf.j2` - -On the system the configuration can be found here: - -`/etc/logrotate.d/kibana` - -Besides logs any other data is depenedant on user usage (Dashboards, queries etc). Kibana stores that kind of data in ElasticSearch under the `.kibana` index. - -### Kubernetes - -The kubelet and container runtime (Docker) do not run in containers. On machines with systemd they write to journald. - -Everything a containerized application writes to stdout and stderr is redirected to the Docker logging driver (`json-file`), which is configured to rotate logs automatically. - -In the default configuration `/core/src/ansible/roles/docker/defaults/main.yml` the following values can be tweaked regarding storage: - -```yaml -docker_logging: - log_opts: - # The maximum size of the log before it is rolled. A positive integer plus a modifier representing the unit of measure (k, m, or g). - max_file_size: "10m" - # The maximum number of log files that can be present. If rolling the logs creates excess files, the oldest file is removed. - max_files: 2 -``` - -On the system the configuration can be found here: - -`/etc/docker/daemon.json` - -### Prometheus - -In the default configuration `/core/src/ansible/roles/prometheus/defaults/main.yml` the following values can be tweaked to control the amount of storage used by Prometheus: - -```yaml -# The path where Prometheus stores its data -prometheus_db_dir: /var/lib/prometheus - -# The time it will retain the data before it gets deleted -prometheus_storage_retention: "30d" - -prometheus_global: -# The interval it will use to scrape the data from the sources -scrape_interval: 15s -``` - -The size of the data which Prometheus will scrape and retain is dependant on the cluster size (Kafka/Kubernetes nodes) and the scrape interval. The [Prometheus storage documentation](https://prometheus.io/docs/prometheus/latest/storage/) will help you determine how much data might be generated with a certain scrape interval and clustersize. This can then be used to determine a storage retention time in days. Note that one should not plan to use the entire disk space for data retention since it might also be used by other components like Grafana which might be deployed on the same system. - -### Zookeeper - -In the default configuration `core/src/ansible/roles/zookeeper/defaults/main.yml` the following values can be tweaked regarding storage: - -```yaml -# The path where Zookeeper stores its logs -zookeeper_log_dir: /var/log/zookeeper - -# The max size a logfile can have -zookeeper_rolling_log_file_max_size: 10MB - -# How many logfiles can be retained before rolling over -zookeeper_max_rolling_log_file_count: 10 -``` +- [Prerequisites for Epiphany](./howto/PREREQUISITES.md) + - Epicli + - [Run Epicli from Docker image](./howto/PREREQUISITES.md#run-epicli-from-docker-image) + - [Run Epicli directly from OS](./howto/PREREQUISITES.md#run-epicli-directly-from-os) + - [Epicli development](./howto/PREREQUISITES.md#epicli-development) + - Legacy + - [Run Docker image for deployment](./howto/PREREQUISITES.md#run-docker-image-for-deployment) + - [Run directly from OS](./howto/PREREQUISITES.md#run-directly-from-os) + - [Run Docker image for development](./howto/PREREQUISITES.md#run-docker-image-for-development) + - [Note for Windows users](./howto/PREREQUISITES.md#note-for-windows-users) + - [Note about proxies](./howto/PREREQUISITES.md#note-about-proxies) + +- [Epiphany cluster](./howto/CLUSTER.md) + - Epicli + - [How to create an Epiphany cluster on existing infrastructure](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-existing-infrastructure) + - [How to create an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-create-an-epiphany-on-a-cloud-provider) + - [How to delete an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-delete-an-epiphany-cluster-on-a-cloud-provider) + - [How to create an offline installation of for Epiphany cluster](./howto/CLUSTER.md#how-to-create-an-offline-installation-for-an-Epiphany-cluster) + - [Single machine cluster](./howto/CLUSTER.md#single-machine-cluster) + - [How to scale components](./howto/CLUSTER.md#how-to-scale-components) + - Legacy + - [How to create an Epiphany legacy cluster on premise](./howto/CLUSTER.md#how-to-create-an-epiphany-legacy-cluster-on-premise) + - [How to create an Epiphany legacy cluster on Azure](./howto/CLUSTER.md#how-to-create-an-epiphany-legacy-cluster-on-azure) + - [How to create legacy production environment on Azure](./howto/CLUSTER.md#how-to-create-legacy-production-environment-on-azure) + - [Single machine legacy cluster](./howto/CLUSTER.md#single-machine-legacy-cluster) + - [How to scale Kubernetes and Kafka on a legacy cluster](./howto/CLUSTER.md#how-to-scale-kubernetes-and-kafka-on-a-legacy-cluster) + - [Build artifacts](./howto/CLUSTER.md#build-artifacts) + - [Kafka replication and partition setting](./howto/CLUSTER.md#kafka-replication-and-partition-setting) + - [RabbitMQ installation and setting](./howto/CLUSTER.md#rabbitmq-installation-and-setting) + +- [Monitoring](./howto/MONITORING.md) + - Epicli + - [How to configure Prometheus alerts](./howto/MONITORING.md#how-to-configure-prometheus-alerts) + - Legacy + - [How to configure Prometheus alerts in a legacy cluster](./howto/MONITORING.md#how-to-configure-prometheus-alerts-in-a-legacy-cluster) + - [Import and create of Grafana dashboards](./howto/MONITORING.md#import-and-create-of-grafana-dashboards) + - [How to configure Kibana](./howto/MONITORING.md#how-to-configure-kibana) + - [How to configure scalable Prometheus setup](./howto/MONITORING.md#how-to-configure-scalable-prometheus-setup) + - [How to configure Azure additional monitoring and alerting](./howto/MONITORING.md#how-to-configure-azure-additional-monitoring-and-alerting) + - [How to configure AWS additional monitoring and alerting](./howto/MONITORING.md#how-to-configure-aws-additional-monitoring-and-alerting) + +- [Kubernetes](./howto/KUBERNETES.md) + - Epicli + - TODO + - Legacy + - [How to expose service through HA Proxy load balancer](./howto/KUBERNETES.md#how-to-expose-service-through-ha-proxy-load-balancer) + - [How to do Kubernetes RBAC](./howto/KUBERNETES.md#how-to-do-kubernetes-rbac) + - [How to run an example app](./howto/KUBERNETES.md#how-to-run-an-example-app) + - [How to set resource requests and limits for Containers](./howto/KUBERNETES.md#how-to-set-resource-requests-and-limits-for-containers) + - [How to run CronJobs](./howto/KUBERNETES.md#how-to-run-cronjobs) + - [How to test the monitoring features](./howto/KUBERNETES.md#how-to-test-the-monitoring-features) + - [How to run chaos on Epiphany Kubernetes cluster and monitor it with Grafana](./howto/KUBERNETES.md#how-to-run-chaos-on-epiphany-kubernetes-cluster-and-monitor-it-with-grafana) + - [How to test the central logging features](./howto/KUBERNETES.md#how-to-test-the-central-logging-features) + - [How to tunnel Kubernetes dashboard from remote kubectl to your PC](./howto/KUBERNETES.md#how-to-tunnel-kubernetes-dashboard-from-remote-kubectl-to-your-pc) + +- [Upgrade](./howto/UPGRADE.md) + - [How to upgrade Kubernetes cluster](./howto/UPGRADE.md#how-to-upgrade-kubernetes-cluster) + - [How to upgrade Kubernetes cluster from 1.13.0 to 1.13.1](./howto/UPGRADE.md#how-to-upgrade-kubernetes-cluster-from-1130-to-1131) + - [How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch](./howto/UPGRADE.md#how-to-upgrade-kubernetes-cluster-from-1131-to-11310--latest-patch) + - [How to upgrade Kafka cluster](./howto/UPGRADE.md#how-to-upgrade-Kafka-cluster) + +- [Security](./howto/SECURITY.md) + - Epicli + - [How to use TLS/SSL certificate with HA Proxy](./howto/SECURITY.md#how-to-use-tls/ssl-certificate-with-ha-proxy) + - [How to enable AWS disk encryption](./howto/SECURITY.md#how-to-enable-AWS-disk-encryption) + - Legacy + - [How to use TLS/SSL certificate with HA Proxy in a legacy cluster](./howto/SECURITY.md#how-to-use-tls/ssl-certificate-with-ha-proxy-in-a-legacy-cluster) + - [How to enable or disable network traffic - firewall](./howto/SECURITY.md#how-to-enable-or-disable-network-traffic) + - [Client certificate for Azure VPN connection](./howto/SECURITY.md#client-certificate-for-azure-vpn-connection) + - [How to set HA Proxy load balancer to minimize risk of Slowloris like attacks](./howto/SECURITY.md#how-to-set-HA-Proxy-load-balancer-to-minimize-risk-of-Slowloris-like-attacks) + - [How to use Kubernetes Secrets](./howto/SECURITY.md#how-to-use-kubernetes-secrets) + - [How to authenticate to Azure AD app](./howto/SECURITY.md#how-to-authenticate-to-azure-ad-app) + +- [Databases](./howto/DATABASES.md) + - Epicli + - TODO + - Legacy + - [How to configure PostgreSQL](./howto/DATABASES.md#how-to-configure-postgresql) + - [How to configure PostgreSQL replication](./howto/DATABASES.md#how-to-configure-postgresql-replication) + +- [Data and log retention](./howto/RETENTION.md) + - Epicli + - TODO + - Legacy + - [Elasticsearch](./howto/RETENTION.md#elasticsearch) + - [Grafana](./howto/RETENTION.md#grafana) + - [Kafka](./howto/RETENTION.md#kafka) + - [Kibana](./howto/RETENTION.md#kibana) + - [Kubernetes](./howto/RETENTION.md#kubernetes) + - [Prometheus](./howto/RETENTION.md#prometheus) + - [Zookeeper](./howto/RETENTION.md#zookeeper) diff --git a/docs/home/RESOURCES.md b/docs/home/RESOURCES.md index 49b122ca87..da504e516d 100644 --- a/docs/home/RESOURCES.md +++ b/docs/home/RESOURCES.md @@ -10,6 +10,7 @@ Here are some materials concerning Epiphany tooling and cluster components - bot - AWS use case [example](https://www.terraform.io/intro/getting-started/build.html) 3. [Ansible](https://www.ansible.com/) - [Intro to playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html) +4. [Azure-cli](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest) ## Cluster Components diff --git a/docs/home/TROUBLESHOOTING.md b/docs/home/TROUBLESHOOTING.md index db71c938bc..43460ba79e 100644 --- a/docs/home/TROUBLESHOOTING.md +++ b/docs/home/TROUBLESHOOTING.md @@ -1,10 +1,10 @@ -# Troubleshooting Guide +# Troubleshooting -## Additional Links +## Epicli -[Kubernetes troubleshooting](https://kubernetes.io/docs/setup/independent/troubleshooting-kubeadm/) +TODO -## Installation +## Legacy ### Service Principal @@ -20,7 +20,20 @@ Timestamp: 2018-07-18 08:30:12Z","error_codes":[70001],"timestamp":"2018-07-18 0 Simply re-launch the command line and the Service Principal should be propagated. Repeat if necessary. This is not very common but has been seen. -### Kubernetes +### Terraform + +The Terraform backend feature along with Azure Service Principal is the default configuration. This allows for multiple team members to modify the IaaS (VM) services on Azure. This works as expected from most networks. However, we have seen an error generated by Terraform on certain networks. This can be resolved simply by setting two options in the `data.yaml` file for your given environment. These are as follows: + +```yaml +# Comments excluded here for clarity +terraform: + service_principal: + enable: false + backend: + enable: false +``` + +## Kubernetes Sometimes Google has a connection issue with pulling down images. You may see something like below: @@ -42,16 +55,3 @@ ERROR org.apache.kafka.common.errors.InvalidReplicationFactorException: Replicat This issue is saying the a replication of 1 is being attempted but there are no brokers '0'. This means that the kafka broker(s) are not running any longer. Kafka will start and attempt to establish connections etc. and if unable it will shutdown and log the message. So, when the verification script runs it will not be able to find a local broker (runs on each broker). Take a look at syslog/dmesg and run `sudo systemctl status kafka`. Most likely it is related to security (TLS/SSL) and/or network but it can also be incorrect settings in the config file `/opt/kafka/config/server.properties`. Correct and rerun the automation. - -## Terraform - -The Terraform backend feature along with Azure Service Principal is the default configuration. This allows for multiple team members to modify the IaaS (VM) services on Azure. This works as expected from most networks. However, we have seen an error generated by Terraform on certain networks. This can be resolved simply by setting two options in the `data.yaml` file for your given environment. These are as follows: - -```yaml -# Comments excluded here for clarity -terraform: - service_principal: - enable: false - backend: - enable: false -``` diff --git a/docs/home/howto/CLUSTER.md b/docs/home/howto/CLUSTER.md new file mode 100644 index 0000000000..8e3a5fd23c --- /dev/null +++ b/docs/home/howto/CLUSTER.md @@ -0,0 +1,413 @@ +## Epicli + +### How to create an Epiphany cluster on existing infrastructure + +Epicli has the ability to setup a cluster on infrastructure provided by you. These can be either bare metal machines or VM's and should meet the following requirements: + +*Note. Hardware requirements are not listed since this dependends on use-case, component configuration etc.* + +1. All the machines are connected by a network or virtual network of some sorts and can communicate which each other. +2. Running one of the following Linux distributions: + - Redhat 7.4+ + - CentOS 7.4+ + - Ubuntu 18.04 + Other distributions/version might work but are un-tested. +3. All machines should be accessible through SSH with a set of SSH keys you provide and configure on each machine yourself. +4. A provisioning machine that: + - Has access to the SSH keys + - Is on the same network as your cluster machines + - Has Epicli running. + *Note. To run Epicli check the [Prerequisites](./PREREQUISITES.md)* + +To setup the cluster do the following steps from the provisioning machine: + +1. First generate a minimal data yaml file: + + ```shell + epicli init -p any -n newcluster + ``` + + The `any` provider will tell Epicli to create a minimal data config which does not contain any cloud provider related information. If you want full control you can add the `--full` flag which will give you a configuration with all parts of a cluster that can be configured. + +2. Open the configuration file and setup the `admin_user` data: + + ```yaml + admin_user: + key_path: /path/to/your/ssh/keys + name: user_name + ``` + Here you should specify the path to the SSH keys and the admin user name which will be used by Anisble to provision the cluster machines. + +3. Define the components you want to install and link them to the machines you want to install them on: + + Under the `components` tag you will find a bunch of definitions like this one: + + ```yaml + kubernetes_master: + count: 1 + machines: + - default-k8s-master + ``` + + The `count` specifies how much machines you want to provision with this component. The `machines` tag is the array of machine names you want to install this component on. Note that the `count` and the number of `machines` defined must match. If you don't want to use a component you can set the `count` to 0 and remove the `machines` tag. Finally a machine can be used by multiple component since multiple components can be installed on one machine of desired. + + You will also find a bunch of `infrastructure/machine` definitions like below: + + ```yaml + kind: infrastructure/machine + name: default-k8s-master + provider: any + specification: + hostname: master + ip: 192.168.100.101 + ``` + + Each machine name used when setting up the component layout earlier must have such a configuration where the `name` tag matches with the defined one in the components. The `hostname` and `ip` fields must be filled to match the actual cluster machines you provide. Ansible will use this to match the machine to a component which in turn will determin which roles to install on the machine. + +4. Finally start the deployment with: + + ```shell + epicli apply -f newcluster.yml --no-infra + ``` + + This will create the inventory for Ansible based on the component/machine definitions made inside the `newcluster.yml` and let Absible deploy it. Note that the `--no-infra` is important since it tells Epicli to skip the Terraform part. + +### How to create an Epiphany cluster on a cloud provider + +Epicli has the ability to setup a cluster on one of the following cloud providers: + +- Azure +- AWS + +Under the hood it uses [Terraform](https://www.terraform.io/) to create the virtual infrastructure before it applies our [Anisble](https://www.ansible.com/) playbooks to provision the VM's. + +You need the following prerequisites: + +1. Access to one of the supported cloud providers, `aws` or `azure`. +2. Adequate resources to deploy a cluster on the cloud provider. +3. A set of SSH keys you provide. +4. A provisioning machine that: + - Has access to the SSH keys + - Has Epicli running. + *Note. To run Epicli check the [Prerequisites](./PREREQUISITES.md)* + +To setup the cluster do the following steps from the provisioning machine: + +1. First generate a minimal data yaml file: + + ```shell + epicli init -p aws/azure -n newcluster + ``` + + The `provider` flag should be either `aws` or `azure` and will tell Epicli to create a data config which contains the specifics for that cloud provider. If you want full control you can add the `--full` flag which will give you a config with all parts of a cluster that can be configured. + +2. Open the configuration file and setup the `admin_user` data: + + ```yaml + admin_user: + admin_user: + key_path: /path/to/your/ssh/keys + name: user_name + ``` + Here you should specify the path to the SSH keys and the admin user name which will be used by Anisble to provision the cluster machines. + + On `Azure` the name you specify will be configured as the admin name on the VM's. + + For `AWS` the admin name is already specified and is dependent on the Linux distro image you are using for the VM's: + + - Username for Ubuntu Server: `ubuntu` + - Username for For Redhat: `ec2-user` + +3. Setup the cloud specific data: + + To let Terraform access the cloud providers you need to setup some additional cloud configuration. + + AWS: + + ```yaml + cloud: + region: eu-west-2 + credentials: + key: aws_key + secret: aws_secret + use_public_ips: false + ``` + + The [region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) lets you chose the most optimal place to deploy your cluster. The `key` and `secret` are needed by Terraform and can be generated in the AWS console. More information about that [here](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) + + Azure: + + ```yaml + cloud: + region: West Europe + subscription_name: Subscribtion_name + use_service_principal: false + use_public_ips: false + ``` + + The [region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) lets you chose the most optimal place to deploy your cluster. The `subscription_name` is the Azure subscribtion under which you want to deploy the cluster. + + Terraform will ask you to sign in to your Microsoft Azure subscibtion when it prepares to build/modify/destroy the infrastructure on `azure`. In case you need to share cluster managment with other people you can set the `use_service_principal` tag to true. This will create a service principle and uses it to manage the resources. + + For both `aws`and `azure` there is a `use_public_ips` tag. When this is true the VM's will also have a direct inferface to the internet. While this is easy for setting up a cluster for testing it should not be used in production. A VPN setup should be used which we will document in a different section (TODO). + +4. Define the components you want to install: + + Under the `components` tag you will find a bunch of definitions like this one: + + ```yaml + kubernetes_master: + count: 1 + ``` + + The `count` specifies how much VM's you want to provision with this component. If you don't want to use a component you can set the `count` to 0. + + Note that for each cloud provider Epicli already has a default VM configuration for each component. If you need more control over the VM's, generate a config with the `--full` flag. Then each component will have an additional machine tag: + + ```yaml + kubernetes_master: + count: 1 + machine: kubernetes-master-machine + ... + ``` + + This links to a `infrastructure/virtual-machine` document which can be found inside the same configuration file. It gives you full control over the VM config (size, storage, provision image, security etc.). More details on this will be documented in a different section (TODO). + +5. Finally start the deployment with: + + ```shell + epicli apply -f newcluster.yml + ``` + +### How to delete an Epiphany cluster on a cloud provider + +Epicli has a delete command to remove a cluster from a cloud provider (AWS, Azure). With Epicli run the following: + + ```shell + epicli apply -b /path/to/cluster/build/folder + ``` + +From the defined cluster build folder it will take the information needed to remove the resources from the cloud provider. + +### How to create an offline installation for an Epiphany cluster + +TODO + +### Single machine cluster + +TODO + +### How to scale components + +TODO + +## Legacy + +### How to create an Epiphany legacy cluster on premise + +0. Pull `core` repository and if needed `data` repository (contains data.yaml files that can be used as example or base for creating your own data.yaml). + +1. Prepare your VM/Metal servers: + 1. Install one of supported OS: RedHat 7.4+, Ubuntu 18.04+ + 2. Create user account with sudo privileges and nopasswd that will use rsa key for login. + 3. Assign static IP addresses for each of the machines - those addresses should not change after cluster creation. + 4. Assign hostnames for machines. + 5. Ensure machines have internet access - it will be needed during Epiphany execution. + 6. Machines will strongly utilize communication between each other, so ensure this communication does not go through proxy. + 7. Note down IP addresses and hostnames of your machines. + +2. If you need you can create new directory in `repository_path/data/your_platform/` or you can use existing profile from data repository. Where `your_platform` can be `vmware`, `vbox`, `metal`. +3. Create or modify data.yaml. +4. Fill in data.yaml with hostname information (`nodes[*]/hosts/name`). +5. Fill in data.yaml with IP information (`nodes[*]/hosts/ips/public`). +6. You can adjust roles for each machine - according to your needs (`nodes[*]/ansible_roles`). +7. Run `bash epiphany -a -b -i -p your_platform -f your_profile` in main epiphany directory. Do not use trailing slash after profile name or as prefix to infrastructure. +8. Store artifacts in `/build` directory securely. Keep those files in order to upgrade/scale your cluster. + +### How to create an Epiphany legacy cluster on Azure + +0. Pull core repository and if needed data repository (contains data.yaml files that can be used as example or base for creating your own data.yaml). + +1. If you need you can create new directory in `repository_path/data/azure/infrastructure/` or you can use existing profile from data repository. + +2. Fill/modify content in the `data.yml` file in `repository_path/data/azure/infrastructure/your_profile` according to your needs. Please, make sure you have enough free public ips/cores assigned to your subscription. + + 1. Data.yaml files can be very verbose and at the beginning you can find difficulties modifying it, especially when defining large clusters with many virtual machines. Instead of defining huge data.yaml file - you can use template. + 2. Look at data repository, there is a template for Azure environments in path `repository_path/data/azure/infrastructure/epiphany-template` + 3. Create folder and `basic-data.yaml` file in it (like `/infrastructure/epiphany-rhel-playground/basic-data.yaml`). This file contains basic data for new cluster like subscription, number of VMs, or keys location. + 4. Execute Epiphany engine with following command when using template file: `bash epiphany -a -b -i -f infrastructure/your_profile -t /infrastructure/epiphany-template` + +3. If you executed point 2.4 - skip next step and go to 5. + +4. Run `bash epiphany -a -b -i -f infrastructure/your_profile` in main epiphany directory. Do not use trailing slash after profile name or as prefix to infrastructure. + +5. The first you run the above command line it will prompt you to login to Microsoft and show you something like the following: + + ```text + To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code DBD7WRF3H to authenticate. + ``` + +6. Store artifacts in `/build` directory securely. Keep those files in order to upgrade/scale your cluster. + + Follow the instructions and a token will be generated in your home directory and then a Service Principal will be created and you will not be prompted for this again. + +7. Go to section [Azure post deployment manual steps](#azure-post-deployment-manual-steps) that may be applicable for your deployment. + +### How to create legacy production environment on Azure + +Keep this in mind that Epiphany will create public IPs for each of the machines, you can remove it but running Epiphany again on the same cluster will recreate public IPs. + +There are no manual steps required when you finished with [How to create an Epiphany cluster on Azure](#how-to-create-an-epiphany-cluster-on-azure) until you decide to move to `production environment` where cluster's virtual machines `must not` be exposed to internet (except load balancer - HAProxy role). + +Production environment on cloud should be composed of two elements: + +1. Demilitarized (`DMZ`) group that contains only load balancer (HAProxy role) +2. Applications (`APPS`) group that contains all other roles + +Both elements are deployed independently (for now) that is why some manual steps, that will be described in this chapter, are required. + +#### 1. DMZ group + +DMZ group should contain HAProxy role that is used for load balancing and TLS termination. VM that hosts HAProxy should be `the only one` accessible from internet. You can see DMZ implementation with VPN for Epiphany build cluster `repository_path/data/azure/infrastructure/epiphany-bld-dmz`. + +#### 2. APPS group + +APPS group contains all features/roles required by your installation - this group should contain (you can enable or disable it) also contain VPN connection so you can access dashboards and logs. You can see APPS group implementation with VPN for Epiphany build cluster `repository_path/data/azure/infrastructure/epiphany-bld-apps`, there is nothing special with this configuration - normal Epiphany data.yaml with VPN enabled (just don't forget to specify you VPN' client certificate). + +When you executed two deployments you should get two resource groups (dmz, apps) with two different VNETs and VPNs. +Now manual steps goes: + +1. Peer you VNET's. Go to VNET setting blade and add peering to another vnet - you have to do it twice, both ways. + +2. Add monitoring endpoints for Prometheus. Load balancer (HAProxy) is separate deployment (for now), but still we have to monitor and take logs from it. That is why we have to add scrape configs for Prometheus (monitoring) + + - SSH into monitoring machine and add `two` files in folder `/etc/prometheus/file_sd/` + + ```yaml + # OS Monitoring - haproxy-vm-node + - targets: ['HAPROXY_MACHINE_PRIVATE_IP:9100'] + labels: + "job": "node" + ``` + + ```yaml + # HAProxy monitoring - haproxy-exporter + - targets: ['HAPROXY_MACHINE_PRIVATE_IP:9101'] + labels: + "job": "haproxy" + ``` + +3. ... and configure address for Elasticsearch (logging) + + - SSH into Load Balancer (HAProxy) machine, and edit file `/etc/filebeat/filebeat.yml`. + - Find `### KIBANA ###` section and add private IP address of Logging VM (`Kibana`) as host value + - Find `### OUTPUTS ###` section and add private IP address of Logging VM (`Elasticsearch`) as host value + +4. For security reasons you should also disassociate public IPs from your APPS virtual machines. + +5. Ensure you defined firewall settings for public VM (load balancer): [How to enable/disable network traffic- firewall](#how-to-enable-disable-network-traffic) + +### Single machine legacy cluster + +In certain circumstances it might be desired to run an Epiphany cluster on a single machine. There are 2 example data.yamls provided for baremetal and Azure: + +- `/core/data/metal/epiphany-single-machine/data.yaml` +- `/core/data/azure/infrastructure/epiphany-single-machine/data.yaml` + +These will install the following minimal set of components on the machine: + +- kubernetes master (Untainted so it can run and manage deployments) +- node_exporter +- prometheus +- grafana +- rabbitmq +- postgresql (for keycloak) +- keycloak (2 instances) + +This bare installation will consume arround 2.8Gb of memory with the following base memory usage of the different components: + +- kubernetes : 904 MiB +- node_exporter : 38 MiB +- prometheus : 133 MiB +- grafana : 54 MiB +- rabbitmq : 85 MiB +- postgresql : 35 MiB +- keycloak : 1 Gb + +Additional resource consumption will be highly dependant on how the cluster is utilized and it will be up to the product teams to define there hardware requirements. The absolute bare minimum this cluster was tested on was a quadcore CPU with 8Gb of ram and 60Gb of storage. However a minimum of an 8 core CPU with 16Gb of ram and 100Gb of storage would be recommended. + +### How to scale Kubernetes and Kafka on a legacy cluster + +#### Scaling Kubernetes + +For Azure specific deployment configuration for Kubernetes Node looks like that: + +```yaml +vms: + - name: vm-k8s-node + size: Standard_DS1_v2 + os_type: linux + count: 1 + bastian_host: false + # roles are how you define a grouping of nodes. These values will be used to create an inventory of your cluster + # Must be a member of the 'role' in core + roles: + - linux + - worker + - node_exporter + - filebeat + - reboot +``` + +There is 1 worker role defined - it means only one Kubernetes node virtual machine will be created and configured to join Kubernetes cluster. When Epiphany deployment was created with one Kubernetes node and then you decide to have more nodes you can simply change + +```yaml +count: 1 +``` + +to + +```yaml +count: 2 +``` + +and wait for add new node. It is important to have your build folder from initial deployment so now state will be automatically refreshed with no downtime. For more information about build folder go to [Build artifacts](#build-artifacts) section. + +For all other deployments (Metal, VMWare, VirtualBox, etc.) you just have to add another definition for machine with worker role. + +#### Scaling Kafka + +Scaling Kafka looks exactly the same like scaling Kubernetes. Once changed `count:` property from `1` to `n` and executed Epiphany you will have `n` Kafka machines. + +To add new Kafka broker to non-Azure deployment looks the same as adding new Kubernetes node. + +## Build artifacts + +Epiphany engine produce build artifacts during each deployment. Those artifacts contains: + +- Generated terraform files. +- Generated terraform state files. +- Generated cluster manifest file. +- Generated ansible files. +- Azure login credentials for `service principal` if deploying to Azure. + +Artifacts contains sensitive data so it is important to keep it in safe place like `private GIT repository` or `storage with limited access`. Generated build is also important in case of scaling or updating cluster - you will it in build folder in order to edit your cluster. + +Epiphany creates (or use if you don't specified it to create) service principal account which can manage all resources in subscription, please store build artifacts securely. + +## Kafka replication and partition setting + +When planning Kafka installation you have to think about number of partitions and replicas since it is strongly related to throughput of Kafka and its reliability. By default Kafka's `replicas` number is set to 1 - you should change it in `core/src/ansible/roles/kafka/defaults` in order to have partitions replicated to many virtual machines. + +```yaml + ... + replicas: 1 # Default to at least 1 (1 broker) + partitions: 8 # 100 x brokers x replicas for reasonable size cluster. Small clusters can be less + ... +``` + +You can read more [here](https://www.confluent.io/blog/how-choose-number-topics-partitions-kafka-cluster) about planning number of partitions. + +## RabbitMQ installation and setting + +To install RabbitMQ in single mode just add rabbitmq role to your data.yaml for your server and in general roles section. All configuration on RabbitMQ - e.g. user other than guest creation should be performed manually. diff --git a/docs/home/howto/DATABASES.md b/docs/home/howto/DATABASES.md new file mode 100644 index 0000000000..2a7496387b --- /dev/null +++ b/docs/home/howto/DATABASES.md @@ -0,0 +1,32 @@ +## Epicli + +TODO + +## Legacy + +### How to configure PostgreSQL + +To configure PostgreSQL login to server using ssh and switch to postgres user with command: + +```bash +sudo -u postgres -i +``` + +And then configure database server using psql according to your needs and +PostgreSQL documentation, to which link you can find at + +### How to configure PostgreSQL replication + +In order to configure PostgreSQL replication add to your data.yaml a block similar to the one below to core section: + +```yaml + postgresql: + replication: + enable: yes + user: your-postgresql-replication-user + password: your-postgresql-replication-password + max_wal_senders: 10 # (optional) - default value 5 + wal_keep_segments: 34 # (optional) - default value 32 +``` +If enable is set to yes in replication then Epiphany will automatically create cluster of master and slave server with replication user with name and password +specified in data.yaml. diff --git a/docs/home/howto/KUBERNETES.md b/docs/home/howto/KUBERNETES.md new file mode 100644 index 0000000000..40215a9557 --- /dev/null +++ b/docs/home/howto/KUBERNETES.md @@ -0,0 +1,197 @@ +## Epicli + +TODO + +## Legacy + +### How to expose service through HA Proxy load balancer + +1. Add haproxy role to your data.yaml +2. Create a folder repository_path/core/src/ansible/roles/haproxy/vars/ +3. Create a file repository_path/core/src/ansible/roles/haproxy/vars/main.yml: +4. Add to repository_path/core/src/ansible/roles/haproxy/vars/main.yml content: + + ```yaml + --- + service_port: your_service_port + ``` + + Where `your_service_port` is a port where your service is exposed using NodePort. + +## How to do Kubernetes RBAC + +Kubernetes that comes with Epiphany has an admin account created, you should consider creating more roles and accounts - especially when having many deployments running on different namespaces. + +To know more about RBAC in Kubernetes use this [link](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) + +## How to run an example app + +Here we will get a simple app to run using Docker through Kubernetes. We assume you are using Windows 10, have an Epiphany cluster on Azure ready and have an Azure Container Registry ready (might not be created in early version Epiphany clusters - if you don't have one you can skip to point no 11 and test the cluster using some public app from the original Docker Registry). Steps with asterisk can be skipped. + +1. Install [Chocolatey](https://chocolatey.org/install) + +2. Use Chocolatey to install: + + - Docker-for-windows (`choco install docker-for-windows`, requires Hyper-V) + - Azure-cli (`choco install azure-cli`) + +3. Make sure Docker for Windows is running (run as admin, might require a restart) + +4. Run `docker build -t sample-app:v1 .` in examples/dotnet/epiphany-web-app. + +5. *For test purposes, run your image locally with `docker run -d -p 8080:80 --name myapp sample-app:v1` and head to `localhost:8080` to check if it's working. + +6. *Stop your local docker container with: `docker stop myapp` and run `docker rm myapp` to delete the container. + +7. *Now that you have a working docker image we can proceed to the deployment of the app on the Epiphany Kubernetes cluster. + +8. Run `docker login myregistry.azurecr.io -u myUsername -p myPassword` to login into your Azure Container Registry. Credentials are in the `Access keys` tab in your registry. + +9. Tag your image with: `docker tag sample-app:v1 myregistry.azurecr.io/samples/sample-app:v1` + +10. Push your image to the repo: `docker push myregistry.azurecr.io/samples/sample-app:v1` + +11. SSH into your Epiphany clusters master node. + +12. *Run `kubectl cluster-info` and `kubectl config view` to check if everything is okay. + +13. Run `kubectl create secret docker-registry myregistry --docker-server myregistry.azurecr.io --docker-username myusername --docker-password mypassword` to create k8s secret with your registry data. + +14. Create `sample-app.yaml` file with contents: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: sample-app + spec: + selector: + matchLabels: + app: sample-app + replicas: 2 + template: + metadata: + labels: + app: sample-app + spec: + containers: + - name: sample-app + image: myregistry.azurecr.io/samples/sample-app:v1 + ports: + - containerPort: 80 + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + memory: 128Mi + imagePullSecrets: + - name: myregistry + ``` + +15. Run `kubectl apply -f sample-app.yaml`, and after a minute run `kubectl get pods` to see if it works. + +16. Run `kubectl expose deployment sample-app --type=NodePort --name=sample-app-nodeport`, then run `kubectl get svc sample-app-nodeport` and note the second port. + +17. Run `kubectl get pods -o wide` and check on which node is the app running. + +18. Access the app through [AZURE_NODE_VM_IP]:[PORT] from the two previous points - firewall changes might be needed. + +## How to set resource requests and limits for Containers + +When Kubernetes schedules a Pod, it’s important that the Containers have enough resources to actually run. If you schedule a large application on a node with limited resources, it is possible for the node to run out of memory or CPU resources and for things to stop working! It’s also possible for applications to take up more resources than they should. + +When you specify a Pod, it is strongly recommended to specify how much CPU and memory (RAM) each Container needs. Requests are what the Container is guaranteed to get. If a Container requests a resource, Kubernetes will only schedule it on a node that can give it that resource. Limits make sure a Container never goes above a certain value. For more details about the difference between requests and limits, see [Resource QoS](https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md). + +For more information, see the links below: + +- [Kubernetes best practices: Resource requests and limits](https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits) +- [Managing Compute Resources for Containers](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) + +## How to run CronJobs + +1. Follow the previous point using examples/dotnet/Epiaphany.SampleApps/Epiphany.SampleApps.CronApp + +2. Create `cronjob.yaml` file with contents: + + ```yaml + apiVersion: batch/v1beta1 + kind: CronJob + metadata: + name: sample-cron-job + spec: + schedule: "*/1 * * * *" # Run once a minute + failedJobsHistoryLimit: 5 + jobTemplate: + spec: + template: + spec: + containers: + - name: sample-cron-job + image: myregistry.azurecr.io/samples/sample-cron-app:v1 + restartPolicy: OnFailure + imagePullSecrets: + - name: myregistrysecret + ``` + +3. Run `kubectl apply -f cronjob.yaml`, and after a minute run `kubectl get pods` to see if it works. + +4. Run `kubectl get cronjob sample-cron-job` to get status of our cron job. + +5. Run `kubectl get jobs --watch` to see job scheduled by the “sample-cron-job” cron job. + +## How to test the monitoring features + +Prerequisites: Epiphany cluster on Azure with at least a single VM with `prometheus` and `grafana` roles enabled. + +1. Copy ansible inventory from `build/epiphany/*/inventory/` to `examples/monitoring/` + +2. Run `ansible-playbook -i NAME_OF_THE_INVENTORY_FILE grafana.yml` in `examples/monitoring` + +3. In the inventory file find the IP adress of the node of the machine that has grafana installed and head over to `https://NODE_IP:3000` - you might have to head over to Portal Azure and allow traffic to that port in the firewall, also ignore the possible certificate error in your browser. + +4. Head to `Dashboards/Manage` on the side panel and select `Kubernetes Deployment metrics` - here you can see a sample kubernetes monitoring dashboard. + +5. Head to `http://NODE_IP:9090` to see Prometheus UI - there in the dropdown you have all of the metrics you can monitor with Prometheus/Grafana. + +## How to run chaos on Epiphany Kubernetes cluster and monitor it with Grafana + +1. SSH into the Kubernetes master. + +2. Copy over `chaos-sample.yaml` file from the example folder and run it with `kubectl apply -f chaos-sample.yaml` - it takes code from `github.com/linki/chaoskube` so normal security concerns apply. + +3. Run `kubectl create clusterrolebinding chaos --clusterrole=cluster-admin --user=system:serviceaccount:default:default` to start the chaos - random pods will be terminated with 5s ferquency, configurable inside the yaml file. + +4. Head over to Grafana at `https://NODE_IP:3000`, open a new dashboard, add a panel, set Prometheus as a data source and put `kubelet_running_pod_count` in the query field - now you can see how Kubernetes is replacing killed pods and balancing them between the nodes. + +5. Run `kubectl get svc nginx-service` and note the second port. You can access the nginx page via `[ANY_CLUSTER_VM_IP]:[PORT]` - it is accessible even though random pods carrying it are constantly killed at random, unless you have more vms in your cluster than deployed nginx instances and choose IP of one not carrying it. + +## How to test the central logging features + +Prerequisites: Epiphany cluster on Azure with at least a single VM with `elasticsearch`, `kibana` and `filebeat` roles enabled. + +1. Connect to kubectl using kubectl proxy or directly from Kubernetes master server + +2. Apply from epiphany repository `extras/kubernetes/pod-counter` `pod-counter.yaml` with command: `kubectl apply -f yourpath_to_pod_counter/pod-counter.yaml` + + Paths are system dependend so please be aware of applying correct separator for your operatins system. + +3. In the inventory file find the IP adress of the node of the machine that has kibana installed and head over to `http://NODE_IP:5601` - you might have to head over to Portal Azure and allow traffic to that port in the firewall. + +4. You can right now search for data from logs in Discover section in Kibana after creating filebeat-* index pattern. To create index pattern click Discover, then in Step 1: Define index pattern as filebeat-*. Then click Next step. In Step 2: Configure settings click Create index pattern. Right now you can go to Discover section and look at output from your logs. + +5. You can verify if CounterPod is sending messages correctly and filebeat is gathering them correctly querying for `CounterPod` in search field in Discover section. + +6. For more informations refer to documentation: + +## How to tunnel kubernetes dashboard from remote kubectl to your PC + +1. SSH into server, and forward port 8001 to your machine `ssh -i epi_keys/id_rsa operations@40.67.255.155 -L 8001:localhost:8001` NOTE: substitute IP with your cluster master's IP. + +2. On **remote** host: get admin token bearer: `kubectl describe secret $(kubectl get secrets --namespace=kube-system | grep admin-user | awk '{print $1}') --namespace=kube-system | grep -E '^token' | awk '{print $2}' | head -1` NOTE: save this token for next points. + +3. On **remote** host, open proxy to the dashboard `kubectl proxy` + +4. Now on your **local** machine navigate to `http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/overview?namespace=default` + +5. When prompted to put in credentials, use admin token from the previous point. diff --git a/docs/home/howto/MONITORING.md b/docs/home/howto/MONITORING.md new file mode 100644 index 0000000000..6cb0da3481 --- /dev/null +++ b/docs/home/howto/MONITORING.md @@ -0,0 +1,164 @@ +## Epicli + +### How to configure Prometheus alerts + +TODO + +## Legacy + +### How to configure Prometheus alerts in a legacy cluster + +In order to send messages from Prometheus add monitoring block to your data.yaml similar to the one below: + +```yaml + monitoring: + alerts: + enable: true + handlers: + mail: + smtp_from: 'some-sender@example.com' + smtp_host: 'somesmtp.example.com:587' + smtp_auth_username: 'someusername' + smtp_auth_password: 'somepassword' + smtp_require_tls: true + recipients: ['recipient1@example.com', 'recipient2@example.com'] + rules: + - name: "disk" + expression: ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes) < 99 + duration: 1m #1s, 1m, 1h, 1d, 1w, ... + severity: critical + message: "Disk space Exceeded" + - name: "updown" + expression: up == 0 + duration: 1m #1s, 1m, 1h, 1d, 1w, ... + severity: critical + message: "Instance down" +``` + + monitoring: - this covers whole monitoring section and is needed to define alerts + alerts: - this covers whole alerts section and is needed to define alerts + enable: true - global switch to turn off/on alerts. Set to true enable alerts. + handlers: - this section covers email handlers, right now only email is supported + mail: - global configuration for smtp and email + smtp_from: 'some-sender@example.com' - name of email sender + smtp_host: 'somesmtp.example.com:port' - address of your smtp server with port + smtp_auth_username: 'someusername' - name of your smtp server username + smtp_auth_password: 'somepassword' - password for your smtp server user + smtp_require_tls: true - enabling/disabling tls. Set to true to enable TLS support. + recipients: ['recipient1@example.com', 'recipient2@example.com'] - list of recipients in form + ['recipient1@example.com', 'recipient2@example.com']. At least one recipient has to be declared. + rules: - this section covers rules for Prometheus to enable monitoring. Each of rule have to follow pattern defined below. + - name: "disk" - name of file for Prometheus where rule will be stored. Permitted are alphanumerical characters only. + expression: ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes) < 99 - rule in format of Prometheus queries + duration: 1m #1s, 1m, 1h, 1d, 1w, ... - duration of event after which notification will be sent, follow Prometheus convention + severity: critical - severity label, that will be showed in email sent to users + message: "Disk space Exceeded" - email topic that will be showed in email sent to users + +More information about Prometheus queries you can find under links provided below: + +https://prometheus.io/docs/prometheus/latest/querying/basics/ + +https://prometheus.io/docs/prometheus/latest/querying/examples/ + +Right now we are only supporting email messages, but we are working heavily on introducing integration with Slack and Pager Duty. + +## Import and create of Grafana dashboards + +Epiphany uses Grafana for monitoring data visualization. Epiphany installation creates Prometheus datasource in Grafana, so the only additional step you have to do is to create your dashboard. + +### Creating dashboards + +You can create your own dashboards [Grafana getting started](http://docs.grafana.org/guides/getting_started/) page will help you with it. +Knowledge of Prometheus will be really helpful when creating diagrams since it use [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) to fetch data. + +### Importing dashboards + +There are also many ready to take [Grafana dashboards](https://grafana.com/dashboards) created by community - remember to check license before importing any of those dashboards. +To import existing dashboard: + +1. If you have found dashboard that suits your needs you can import it directly to Grafana going to menu item `Dashboards/Manage` in your Grafana web page. +2. Click `+Import` button. +3. Enter dashboard id or load json file with dashboard definition +4. Select datasource for dashboard - you should select `Prometheus`. +5. Click `Import` + +### Components used for monitoring + +There are many monitoring components deployed with Epiphany that you can visualize data from. The knowledge which components are used is important when you look for appropriate dashboard on Grafana website or creating your own query to Prometheus. + +List of monitoring components - so called exporters: + +- cAdvisor +- HAProxy Exporter +- JMX Exporter +- Kafka Exporter +- Node Exporter +- Zookeeper Exporter + +When dashboard creation or import succeeds you will see it on your dashboard list. + +## How to configure Kibana + +In order to start viewing and analyzing logs with Kibana, you first need to add an index pattern for Filebeat according to the following steps: + +1. Goto the `Management` tab +2. Select `Index Patterns` +3. On the first step define as index pattern: + `filebeat-*` + Click next. +4. Configure the time filter field if desired by selecting `@timestamp`. This field represents the time that events occurred or were processed. You can choose not to have a time field, but you will not be able to narrow down your data by a time range. + +This filter pattern can now be used to query the Elasticsearch indices. + +By default Kibana adjusts the UTC time in `@timestamp` to the browser's local timezone. This can be changed in `Management` > `Advanced Settings` > `Timezone for date formatting`. + +## How to configure scalable Prometheus setup + +If you want to create scalable Prometheus setup you can use federation. Federation lets you scrape metrics from different Prometheus +instances on one Prometheus instance. + +In order to create federation of Prometheus add to your configuration (for example to prometheus.yaml +file) of previously created Prometheus instance (on which you want to scrape data from other +Prometheus instances) to `scrape_configs` section: + +```yaml +scrape_configs: + - job_name: federate + metrics_path: /federate + params: + 'match[]': + - '{job=~".+"}' + honor_labels: true + static_configs: + - targets: + - your-prometheus-endpoint1:9090 + - your-prometheus-endpoint2:9090 + - your-prometheus-endpoint3:9090 + ... + - your-prometheus-endpointn:9090 +``` + +To check if Prometheus from which you want to scrape data is accessible, you can use a command +like below (on Prometheus instance where you want to scrape data): + +`curl -G --data-urlencode 'match[]={job=~".+"}' your-prometheus-endpoint:9090/federate` + +If everything is configured properly and Prometheus instance from which you want to gather data is up +and running, this should return the metrics from that instance. + +## How to configure Azure additional monitoring and alerting + +Setting up addtional monitoring on Azure for redundancy is good practice and might catch issues the Epiphany monitoring might miss like: + +- Azure issues and resource downtime +- Issues with the VM which runs the Epiphany monitoring and Alerting (Prometheus) + +More information about Azure monitoring and alerting you can find under links provided below: + +https://docs.microsoft.com/en-us/azure/azure-monitor/overview + +https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-alerts + +## How to configure AWS additional monitoring and alerting + +TODO diff --git a/docs/home/howto/PREREQUISITES.md b/docs/home/howto/PREREQUISITES.md new file mode 100644 index 0000000000..c142627951 --- /dev/null +++ b/docs/home/howto/PREREQUISITES.md @@ -0,0 +1,274 @@ +## Epicli + +### Run Epicli from Docker image + +There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. + +#### Build Epicli image locally + +1. Install the following dependencies: + + - Python 3.7 + - PIP + - Pipenv + - Docker + +2. Open a terminal in `/core/src/epicli` and run: + + On Linux: + + ```bash + ./build-docker.sh + ``` + + On windows: + + ```bash + ./build-docker.bat + ``` + +#### Pull Epicli image from the registry + +```bash +docker pull epiphanyplatform/epicli:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epicli) for the available tags.* + +#### Running the Epicli image + +To run the image: + +Locally build: + +```bash +docker run -it -v LOCAL_DIR:/shared --rm epicli +``` + +Pulled: + +```bash +docker run -it -v LOCAL_DIR:/shared --rm epiphanyplatform/epicli:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epicli) for the available tags.* + +Where `LOCAL_DIR` should be replaced with the local path to the directory for Epicli input (SSH keys, data yamls) and output (logs, build states). + +### Run Epicli directly from OS + +*Note: Epicli will only run on Lixux or MacOS and not on Windows. This is because Ansible at this point in time does not work on Windows.* + +1. To be able to run the Epicli from your local OS you have to install: + + - Python 3.7 + - PIP + - Pipenv + +2. Open a terminal in `/core/src/epicli` and run: + + ```bash + pipenv install + ``` + + This will create a virtual Python 3.7 environment and install all needed dependencies. + +3. Build the Epicli wheel: + + ```bash + ./build-wheel.sh + ``` + +4. Enter the virtual Python enviroment: + + ```bash + pipenv shell + ``` + +5. Install the Epicli wheel inside the virtual enviroment: + + ```bash + pip install dist/epicli-VERSION-py3-none-any.whl + ``` + +6. Verify the Epicli installation: + + ```bash + epicli --version + ``` + + This should return the version of the CLI deployed. + +Now you can use Epicli inside the created virtual environment. + +### Epicli development + +For setting up en Epicli development environment please refer to this dedicated document [here.](./../DEVELOPMENT.md) + +## Legacy + +### Run Docker image for deployment + +For people who are only using the Epiphany engine to deploy and maintain clusters there is a Dockerfile for the image with the engine already embedded. + +There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. + +#### Build deployment image locally + +```bash +docker build -t epiphany-dev -f core/src/docker/deploy/Dockerfile . +``` + +#### Pull deployment image from the registry + +```bash +docker pull epiphanyplatform/epiphany-deploy:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epiphany-deploy) for the available tags.* + +#### Running the deployment image + +To run the image: + +Locally build: + +```bash +docker run -it -v LOCAL_DATA_DIR:/epiphany/core/data \ + -v LOCAL_BUILD_DIR:/epiphany/core/build \ + -v LOCAL_SSH_DIR:/epiphany/core/ssh \ + --rm epiphany-deploy +``` + +Pulled: + +```bash +docker run -it -v LOCAL_DATA_DIR:/epiphany/core/data \ + -v LOCAL_BUILD_DIR:/epiphany/core/build \ + -v LOCAL_SSH_DIR:/epiphany/core/ssh \ + --rm epiphanyplatform/epiphany-deploy:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epiphany-deploy) for the available tags.* + +```LOCAL_DATA_DIR``` should be the host input directy for your data YAMLs and certificates. ```LOCAL_BUILD_DIR``` should be the host directory where you want the Epiphany engine to write its build output. ```LOCAL_SSH_DIR``` should be the host directory where the SSH keys are stored. If everything is ok you will be presented with a Bash prompt from which one can run the Epiphany engine. Note that when filling in your data YAMLs one needs to specify the paths from the container's point of view. + +[`Azure specific`] Ensure that you have already enough resources/quotas accessible in your region/subscription on Azure before you run Epiphany - depending on your configuration it can create large number of resources. + +### Run directly from OS + +To be able to run the Epiphany engine from your local OS you have to install: + +- Bash 4.4+ + - Should be natively installed on Linux distributions. + - MacOS version of bash most likely needs upgrading. + - For Windows 10 you can install Ubuntu subsystem. + - For Windows 7 see the docker image options below. +- Ansible 2.6+ +- Hashicorp Terraform 0.11.8+ +- jq (JSON Query tool: ) +- Python 2.7 + - jinja2 2.10+ + - jmespath 0.9.3+ +- Git +- Azure CLI 2.0+ +- SSH + +This can both be used for deploying/managing clusters or for development. + +### Run Docker image for development + +To facilitate an easier path for developers to contribute to Epiphany we have a development docker image based on alpine. This image will help to more easily setup a development environment or to develop on systems which do not support Bash like Windows 7. + +The following prerequisites are needed when working with the development image: + +- Docker + - For Windows 7 check [here](https://docs.docker.com/toolbox/toolbox_install_windows) +- Git + +There are 2 ways to get the image, build it locally yourself or pull it from the Epiphany docker registry. + +#### Build dev image locally + +```bash +docker build -t epiphany-dev -f core/src/docker/dev/Dockerfile . +``` + +#### Pull dev image from the registry + +```bash +docker pull epiphanyplatform/epiphany-dev:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epicli) for the available tags.* + +#### Running the dev image + +To run the image: + +Locally build: + +```bash +docker run -it -v LOCAL_DEV_DIR:/epiphany --rm epiphany-dev +``` + +Pulled: + +```bash +docker run -it -v LOCAL_DEV_DIR:/epiphany --rm epiphanyplatform/epiphany-dev:TAG +``` + +*Check [here](https://cloud.docker.com/u/epiphanyplatform/repository/docker/epiphanyplatform/epicli) for the available tags.* + +Where `LOCAL_DEV_DIR` should be replaced with the local path to your local Epiphany repo. This will then be mapped to `epiphany` inside the container. If everything is ok you will be presented with a Bash prompt from which one can run the Epiphany engine while editing the core and data sources on the local OS. Note that when filling in your data YAMLs one needs to specify the paths from the container's point of view. + +## Note for Windows users + +- Watch out for the line endings conversion. By default Git for Windows sets `core.autocrlf=true`. Mounting such files with Docker results in `^M` end-of-line character in the config files. +Use: [Checkout as-is, commit Unix-style](https://stackoverflow.com/questions/10418975/how-to-change-line-ending-settings) (`core.autocrlf=input`) or Checkout as-is, commit as-is (`core.autocrlf=false`). Be sure to use a text editor that can work with Unix line endings (e.g. Notepad++). + +- Remember to allow Docker Desktop to mount drives in Settings -> Shared Drives + +- Escape your paths properly: + + - Powershell example: + ```bash + docker run -it -v C:\Users\USERNAME\git\epiphany:/epiphany --rm epiphany-dev: + ``` + - Git-Bash example: + ```bash + winpty docker run -it -v C:\\Users\\USERNAME\\git\\epiphany:/epiphany --rm epiphany-dev + ``` + +- Mounting NTFS disk folders in a linux based image causes permission issues with SSH keys. When running either the development or deploy image: + +1. Copy the certs on the image: + + ```bash + mkdir -p ~/.ssh/epiphany-operations/ + cp /epiphany/core/ssh/id_rsa* ~/.ssh/epiphany-operations/ + ``` +2. Set the propper permission on the certs: + + ```bash + chmod 400 ~/.ssh/epiphany-operations/id_rsa* + ``` + +## Note about proxies + +To run the legacy Epiphany or the new Epicli from behind a proxy, enviroment variables need to be set. + +When running directly from OS (upper and lowercase are needed because of an issue with the Ansible dependency): + + ```bash + export http_proxy="http://PROXY_SERVER:PORT" + export https_proxy="https://PROXY_SERVER:PORT" + export HTTP_PROXY="http://PROXY_SERVER:PORT" + export HTTPS_PROXY="https://PROXY_SERVER:PORT" + ``` + +Or when running from a Docker image (upper and lowercase are needed because of an issue with the Ansible dependency): + + ```bash + docker run -it -v POSSIBLE_MOUNTS... -e HTTP_PROXY=http://PROXY_SERVER:PORT -e HTTPS_PROXY=http://PROXY_SERVER:PORT http_proxy=http://PROXY_SERVER:PORT -e https_proxy=http://PROXY_SERVER:PORT --rm IMAGE_NAME + ``` diff --git a/docs/home/howto/RETENTION.md b/docs/home/howto/RETENTION.md new file mode 100644 index 0000000000..c43fe9a318 --- /dev/null +++ b/docs/home/howto/RETENTION.md @@ -0,0 +1,145 @@ +An Epiphany cluster has a number of components which log, collect and retain data. To make sure that these do not exceed the usable storage of the machines there running on the following configurations are available. + +## Epicli + +TODO + +## Legacy + +### Elasticsearch + +For managing the data storage that Elasticsearch consumes we use [Elasticsearch Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html). To use it one needs to make sure the elasticsearch-curator is enabled. This role will install and configure the [Elasticsearch Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html) to run in a cronjob to clean up older indices which are older then a certain treshold. + +In the default configuration `/core/src/ansible/roles/elasticsearch-curator/defaults/main.yml` the following values can be tweaked regarding storage: + +```yaml +# Rentention time of Elasticsearch indices in days. +indices_retention_days: 30 +``` + +The size of the storage consumed by Elasticsearch is depenedant on the clustersize and how much logging the deployed application will generate. + +### Grafana + +In the default configuration `/core/src/ansible/roles/grafana/defaults/main.yml` the following values can be tweaked to control the ammount of storage used by Grafana: + +```yaml +# The path where Grafana stores its logs +grafana_logs_dir: "/var/log/grafana" + +# The path where Grafana stores it's (Dashboards DB (SQLLite), sessions, etc) +grafana_data_dir: "/var/lib/grafana" + +grafana_logging: +# Enable or disable log rotation +log_rotate: true + +# Enable or disable daily log rotation +daily_rotate: true + +# Number of days to retain the logs +max_days: 7 +``` + +While logs can be rotated and have a retention time, the ammount of storage used by Grafana is dependant on user usage and dashboard count and cannot be directly controlled. + +## Kafka + +In the default configuration `/core/src/ansible/roles/kafka/defaults/main.yml` the following values can be tweaked regarding storage: + +```yaml +# The path where kafka stores its data +data_dir: /var/lib/kafka + +# The path where kafka stores its logs +log_dir: /var/log/kafka + +# The minimum age of a log file to be eligible for deletion due to age +log_retention_hours: 168 + +# Offsets older than this retention period will be discarded +offset_retention_minutes: 10080 +``` + +The ammount of storage Kafka consumes is dependant on the application running on Epiphany, how many messages producers create and how fast the consumers can consume them. It's up to the application developer to configure a `log_retention_hours` and `offset_retention_minutes` to suite the applications need. + +Since Kafka does not have a mechanism for log rotation we use [logrotate](https://linux.die.net/man/8/logrotate) for this. The template for logrotate can be found here: + +`/core/src/ansible/roles/kafka/templates/logrotate.conf.j2` + +On the system the configuration can be found here: + +`/etc/logrotate.d/kafka` + +### Kibana + +In the default configuration `/core/src/ansible/roles/kibana/defaults/main.yml` the following values can be tweaked regarding storage: + +```yaml +# The path where Kibana stores its logs +kibana_log_dir: /var/log/kibana +``` + +Since Kibana does not have a mechanism for log rotation we use [logrotate](https://linux.die.net/man/8/logrotate) for this. The template for logrotate can be found here: + +`/core/src/ansible/roles/kibana/templates/logrotate.conf.j2` + +On the system the configuration can be found here: + +`/etc/logrotate.d/kibana` + +Besides logs any other data is depenedant on user usage (Dashboards, queries etc). Kibana stores that kind of data in ElasticSearch under the `.kibana` index. + +### Kubernetes + +The kubelet and container runtime (Docker) do not run in containers. On machines with systemd they write to journald. + +Everything a containerized application writes to stdout and stderr is redirected to the Docker logging driver (`json-file`), which is configured to rotate logs automatically. + +In the default configuration `/core/src/ansible/roles/docker/defaults/main.yml` the following values can be tweaked regarding storage: + +```yaml +docker_logging: + log_opts: + # The maximum size of the log before it is rolled. A positive integer plus a modifier representing the unit of measure (k, m, or g). + max_file_size: "10m" + # The maximum number of log files that can be present. If rolling the logs creates excess files, the oldest file is removed. + max_files: 2 +``` + +On the system the configuration can be found here: + +`/etc/docker/daemon.json` + +### Prometheus + +In the default configuration `/core/src/ansible/roles/prometheus/defaults/main.yml` the following values can be tweaked to control the amount of storage used by Prometheus: + +```yaml +# The path where Prometheus stores its data +prometheus_db_dir: /var/lib/prometheus + +# The time it will retain the data before it gets deleted +prometheus_storage_retention: "30d" + +prometheus_global: +# The interval it will use to scrape the data from the sources +scrape_interval: 15s +``` + +The size of the data which Prometheus will scrape and retain is dependant on the cluster size (Kafka/Kubernetes nodes) and the scrape interval. The [Prometheus storage documentation](https://prometheus.io/docs/prometheus/latest/storage/) will help you determine how much data might be generated with a certain scrape interval and clustersize. This can then be used to determine a storage retention time in days. Note that one should not plan to use the entire disk space for data retention since it might also be used by other components like Grafana which might be deployed on the same system. + +### Zookeeper + +In the default configuration `core/src/ansible/roles/zookeeper/defaults/main.yml` the following values can be tweaked regarding storage: + +```yaml +# The path where Zookeeper stores its logs +zookeeper_log_dir: /var/log/zookeeper + +# The max size a logfile can have +zookeeper_rolling_log_file_max_size: 10MB + +# How many logfiles can be retained before rolling over +zookeeper_max_rolling_log_file_count: 10 +``` diff --git a/docs/home/howto/SECURITY.md b/docs/home/howto/SECURITY.md new file mode 100644 index 0000000000..8aeb6cee30 --- /dev/null +++ b/docs/home/howto/SECURITY.md @@ -0,0 +1,211 @@ +## Epicli + +### How to use TLS/SSL certificate with HA Proxy + +TODO + +### How to enable AWS disk encryption + +#### EC2 Root volumes + +Since [May 2019](https://aws.amazon.com/about-aws/whats-new/2019/05/launch-encrypted-ebs-backed-ec2-instances-from-unencrypted-amis-in-a-single-step/) AWS supports the creation of instances from unencrypted AMIs. At this point Terraform does not [support](https://github.com/terraform-providers/terraform-provider-aws/issues/8624) this jet. If you need encrypted root volumes for now you need to supply your own pre-encryped AMIs as specified in the guide [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html). + +We will add this as the functionality becomes available in Terraform. The issue is beeing tracked [here](https://github.com/epiphany-platform/epiphany/issues/381). + +#### Additional EC2 storage + +When defining extra storage inside the `infrastructure/virtual-machine` document one can set the `encryption` flag: + +```yaml +... +additional_disks: + - device_name: "/dev/sdb" + volume_type: gp2 + volume_size: 60 + delete_on_termination: true + encrypted: true +... +``` + +#### EFS storage + +EFS storage is encrypted by default. + +## Legacy + +### How to use TLS/SSL certificate with HA Proxy in a legacy cluster + +If you want to use HAProxy with TLS/SSL certificate follow the instruction below. + +1. Add haproxy_tls_termination role to your data.yaml +2. If you want to use your certificates, you can add to section core to your data.yaml: + + ```yaml + haproxy: + haproxy_certs_dir: your_path_to_certificates + ``` + + Your certificates will be copied and applied automatically to HA Proxy configuration. + + Please be aware that `your_path_to_certificates` cannot contain variables (`$HOME`) or tilde (`~`) as this will make deployment of Epiphany fail. Additionally if you need more than one DNS name for your frontend you need to provide certificates on your own, as there is only one self-signed certificate generated by this role with CN localhost. For multiple backends you need to provide also mapping as described in later part of this document. + +3. If you don't want to apply your certificates that will be generated automatically, then just don't put any certificate in `your_path_to_certificates` or don't put section with `haproxy: haproxy_certs_dir` in your data.yaml + +4. Below you can find example of configuration: + ```yaml + haproxy: + haproxy_certs_dir: /home/epiphany/certs/ + frontend: + - name: https_front + port: 443 + https: yes + backend: + - http_back1 + - http_back2 + domain_backend_mapping: + - domain: backend1.domain.com + backend: http_back1 + - domain: backend2.domain.com + backend: http_back2 + - name: http_front1 + port: 80 + https: no + backend: + - http_back2 + - name: http_front2 + port: 8080 + https: no + backend: + - http_back1 + - http_back2 + domain_backend_mapping: + - domain: http-backend1.domain.com + backend: http_back1 + - domain: http-backend2.domain.com + backend: http_back2 + backend: + - name: http_back1 + server_groups: + - worker + port: 30001 + - name: http_back2 + server_groups: + - worker + - kibana + port: 30002 + ``` + +5. Parameters description: + + `haproxy_certs_dir` - (Optional) Path on machine from which you run Epiphany installer where certificates generated by you are stored. If not one certificate with CN localhost will be generated, works only with one frontend definition, in other cases it won't be able to redirect you to correct backend on HAProxy. + + `frontend` - (Mandatory) At least one frontend configuration must exist, if more than one domain must be supported than `domain_backend_mapping` section is mandatory, as this will make fail. This is a list of frontend, each position has to start with `-`. + + - `name` - (Mandatory) Name of each configuration for frontend. + - `port` - (Mandatory) Port to which frontend should be binding. Must be unique for all frontends in other case it will make HAProxy fail. + - `https` - (Mandatory) Information if https will be used - options `yes`/`no`. If `no`, only http part of configuration for frontend will be generated. + - `backend` - (Mandatory) At least one backend configuration must exist. If `domain_backend_mapping` exists this must match configuration in `domain_backend_mapping` backend section. It always has to match configuration from backend name section. This is a list of backend, each position has to start with `-`. This parameter shows to which backend configuration forward traffic from frontend to backend. + + - `domain_backend_mapping` - (Optional) If this exist at least one domain to backend mapping must exist. Must be provided if more than one domain has to be supported. + + - `domain` - (Mandatory if `domain_backend_mapping` used for each mapping) Domain that matches SSL certificate CN for https configuration and domain name. For http, domain that will be mapped using http header. + - `backend` - (Mandatory if `domain_backend_mapping` used for each mapping) Must match name from backend section + + `backend` - (Mandatory) This is a list of backend, each position has to start with `-`. At least one backend used by frontend must exist. If there won't be a match with each frontend configuration HAProxy will fail to start. + - `name` - (Mandatory) Name of each configuration for backend, must match frontend backend configuration and `domain_backend_mapping` backend part in frontend section. + - `server_groups` - (Mandatory) This is a list of server groups, each position has to start with `-`. At least one `server_group` used by backend must exist. It must match Epiphany role e.g. `kibana`, `worker` etc. + - `port` - (Mandatory) Port on which backend service is exposed. + +### How to enable or disable network traffic + +#### VM Firewall + +Epiphany 1.0 supports firewalld on host machines (RedHat only). You can enable firewall setting `.../security/firewall/enable` to `true` in data.yaml. Remember to allow port 22 to be open in ports_open (`.../security/firewall/ports_open`) dictionary in order to configuration can do its job. + +#### Azure specific - Network Security Group + +Security for internet facing infrastructure is extremely important thing - remember to configure `Network Security Group` rules to allow network traffic only on required ports and directions. You can do it using Azure specific data.yaml in section `.../network_security_group/rules`. Remember to allow port 22 (you can/should remove this rule after deployment) in order to configuration can do its job. + +### Client certificate for Azure VPN connection + +Epiphany will create point to site configuration (if you enable VPN in `.../security/vpn/enable` and specify public key of your certificate, in base64 format, in `public_cert_data` field). For production environments you have to use root certificate from `trusted provider`. +For development purposes you can use self signed certificate which can be generated using powershell: + +When you get root certificate you should generate child certificate(s) that will be distributed to the team that should have VPN access to clusters. +Configuration of client config in data.yaml (`.../security/vpn/client_configuration/root_certificate`) looks like following: + +```yaml +... +root_certificate: + # name is the name of the cert that was created for you by a trusted party OR a name you give a self-signed cert + name: NAME-OF-YOUR-CERTIFICATE + revoked_certificate: + name: NAME-OF-REVOKED-CERTIFICATE + thumbprint: THUMBPRINT-OF-REVOKED-CERTIFICATE + # public_cert_data is the actual base64 public key from your cert. Put it in 'as is'. The '|' tells yaml to use 'as is'. + public_cert_data: | + YOUR-BASE64-CLIENT-AUTH-PUBLIC-KEY +... +``` + +### How to set HA Proxy load balancer to minimize risk of Slowloris like attacks + +1. Add haproxy_tls_termination role to your data.yaml +2. If you want to minimize risk of Slowloris like attacks add to your data.yaml in section for haproxy: + + ```yaml + haproxy: + http_request_timeout: 5s + ``` + + Where http_request_timeout is the number_of_seconds with s after which connection to HAProxy will be terminated by HAProxy. + This parameter is optional, if is not present no timeout http-request in global section of HAProxy configuration will be set. + +Configuration requires to have revoked certificate filled in (for now). + +## How to use Kubernetes Secrets + +Prerequisites: Epiphany Kubernetes cluster + +1. SSH into the Kubernetes master. + +2. Run `echo -n 'admin' > ./username.txt`, `echo -n 'VeryStrongPassword!!1' > ./password.txt` and `kubectl create secret generic mysecret --from-file=./username.txt --from-file=./password.txt` + +3. Copy over `secrets-sample.yaml` file from the example folder and run it with `kubectl apply -f secrets-sample.yaml` + +4. Run `kubectl get pods`, copy the name of one of the ubuntu pods and run `kubectl exec -it POD_NAME -- /bin/bash` with it. + +5. In the pods bash run `printenv | grep SECRET` - Kubernetes secret created in point 2 was attached to pods during creation (take a look at `secrets-sample.yaml`) and are availiable inside of them as an environmental variables. + +## How to authenticate to Azure AD app + +1. Register you application. Go to Azure portal to `Azure Active Directory => App registrations` tab. + +2. Click button `New application registration` fill the data and confirm. + +3. Deploy app from `examples/dotnet/Epiphany.SampleApps/Epiphany.SampleApps.AuthService`. + + This is a test service for verification Azure AD authentication of registered app. ([How to deploy app](#how-to-run-an-example-app)) + +4. Create secret key for your app `settings => keys`. Remember to copy value of key after creation. + +5. Try to authenticate (e.g. using postman) calling service api `/api/auth/` with following Body application/json type parameters : + + ```json + { + "TenantId": "", + "ClientId": "", + "Resource": "https://graph.windows.net/", + "ClientSecret": "" + } + ``` + + - TenantId - Directory ID, which you find in `Azure active Directory => Properties` tab. + + - ClientId - Application ID, which you find in details of previously registered app `Azure Active Directory => App registrations => your app` + + - Resource - is the service root of Azure AD Graph API. The Azure Active Directory (AD) Graph API provides programmatic access to Azure AD through OData REST API endpoints. You can construct your own Graph API URL. ([How to construct a Graph API URL](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api-quickstart)) + + - ClientSecret - Created secret key from 4. point. + +6. The service should return Access Token. diff --git a/docs/home/howto/UPGRADE.md b/docs/home/howto/UPGRADE.md new file mode 100644 index 0000000000..d6368045ac --- /dev/null +++ b/docs/home/howto/UPGRADE.md @@ -0,0 +1,457 @@ +## How to upgrade Kubernetes cluster + +Upgrade procedure might be different for each Kubernetes version. Upgrade shall be done only from one minor version to next minor version. For example, upgrade from 1.9 to 1.11 looks like this: + +```text +1.9.x -> 1.9.y +1.9.y -> 1.10 +1.10 -> 1.11 +``` + +Each version can be upgraded in a bit different way, to find information how to upgrade your version of Kubernetes please use this [guide](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-upgrade/#kubeadm-upgrade-guidance). + +Epiphany uses kubeadm to boostrap a cluster and the same tool is also used to upgrade it. + +Upgrading Kubernetes cluster with running applications shall be done step by step. To prevent your applications downtime you should use at least **two Kubernetes worker nodes** and at least **two instances of each of your service**. + +Start cluster upgrade with upgrading master node. Detailed instructions how to upgrade each node, including master, are described in guide linked above. When Kubernetes master is down it does not affect running applications, at this time only control plane is not operating. **Your services will be running but will not be recreated nor scaled when control plane is down.** + +Once master upgrade finished successfully, you shall start upgrading nodes - **one by one**. Kubernetes master will notice when worker node is down and it will instatiate services on existing operating node, that is why it is essential to have more than one worker node in cluster to minimize applications downtime. + +## How to upgrade Kubernetes cluster from 1.13.0 to 1.13.1 + +Detailed instruction can be found in [Kubernetes upgrade to 1.13 documentation](https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-13/) + +### Ubuntu Server + +#### Upgrade Master + +```bash +# RUN ON MASTER + +1. sudo kubeadm version # should show v1.13.0 +2. sudo kubeadm upgrade plan v1.13.1 + +3. apt update +4. apt-cache policy kubeadm + + +5. sudo apt-mark unhold kubeadm && \ +sudo apt-get update && sudo apt-get install -y kubeadm=1.13.1-00 && \ +sudo apt-mark hold kubeadm + +6. sudo kubeadm version # should show v1.13.1 +7. sudo kubeadm upgrade plan v1.13.1 + +8. sudo kubeadm upgrade apply v1.13.1 + +9. sudo apt-mark unhold kubelet && \ +sudo apt-get update && sudo apt-get install -y kubelet=1.13.1-00 && \ +sudo apt-mark hold kubelet +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Worker nodes will be upgraded one by one - it will prevent application downtime. + +```bash + +# RUN ON WORKER NODE - $NODE + +1. sudo apt-mark unhold kubectl && \ +sudo apt-get update && sudo apt-get install -y kubectl=1.13.1-00 && \ +sudo apt-mark hold kubectl + +# RUN ON MASTER + +2. kubectl drain $NODE --ignore-daemonsets + +# RUN ON WORKER NODE - $NODE + +3. sudo kubeadm upgrade node config --kubelet-version v1.13.1 + +4. sudo apt-get update +5. sudo apt-get install -y kubelet=1.13.1-00 kubeadm=1.13.1-00 + +6. sudo systemctl restart kubelet +7. sudo systemctl status kubelet # should be running + +# RUN ON MASTER + +8. kubectl uncordon $NODE + +9. # go to 1. for next node + +# RUN ON MASTER +10. kubectl get nodes # should return nodes in status "Ready" and version 1.13.1 + +``` + +### RHEL + +#### Upgrade Docker version + +Upgrading Kubernetes to 1.13.1 on RHEL requires Docker upgrade. Newer Docker packages exist in docker-ce repository but you can use newer Docker-ee if you need. Verified Docker versions for Kubernetes are: 1.11.1, 1.12.1, 1.13.1, 17.03, 17.06, 17.09, 18.06. [Go to K8s docs](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.13.md#external-dependencies) + +```bash + +# Remove previous docker version +1 sudo yum remove docker \ + docker-common \ + container-selinux \ + docker-selinux \ + docker-engine +2. sudo rm -rf /var/lib/docker +3. sudo rm -rf /run/docker +4. sudo rm -rf /var/run/docker +5. sudo rm -rf /etc/docker + +# Add docker-ce repository +6. sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo +7. sudo yum makecache fast +8. sudo yum -y install docker-ce-18.06.3.ce-3.el7 + +``` + +#### Upgrade Master + +```bash +# RUN ON MASTER + +1. sudo kubeadm version # should show v1.13.0 +2. sudo kubeadm upgrade plan v1.13.1 + +3. sudo yum install -y kubeadm-1.13.1-0 --disableexcludes=kubernetes + +4. sudo kubeadm version # should show v1.13.1 +5. sudo kubeadm upgrade plan v1.13.1 + +6. sudo kubeadm upgrade apply v1.13.1 + +7. sudo yum install -y kubelet-1.13.1-0 --disableexcludes=kubernetes + +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Worker nodes will be upgraded one by one - it will prevent application downtime. + +```bash + +# RUN ON WORKER NODE - $NODE + +1. yum install -y kubectl-1.13.1-0 --disableexcludes=kubernetes + +# RUN ON MASTER + +2. kubectl drain $NODE --ignore-daemonsets + +# RUN ON WORKER NODE - $NODE + +3. # Upgrade Docker version using instruction from above + +4. sudo kubeadm upgrade node config --kubelet-version v1.13.1 + +5. sudo yum install -y kubelet-1.13.1-0 kubeadm-1.13.1-0 --disableexcludes=kubernetes + +6. sudo systemctl restart kubelet +7. sudo systemctl status kubelet # should be running + +# RUN ON MASTER + +8. kubectl uncordon $NODE + +9. # go to 1. for next node + +# RUN ON MASTER +10. kubectl get nodes # should return nodes in status "Ready" and version 1.13.1 + +``` + +## How to upgrade Kubernetes cluster from 1.13.1 to 1.13.10 / latest patch + +### Ubuntu Server + +#### Upgrade Master + +Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) + +##### > RUN ON MASTER + +1. Check kubeadm version +```bash +kubeadm version +# should show v1.13.1 +``` +2. Find the latest stable 1.13 version +```bash +sudo apt update +apt-cache policy kubeadm +# 1.13.10-0 +``` +3. Drain master in preparation for maintenance +```bash +kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] +# $MASTER should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +4. Wait for all pods to be running and ready + +5. Install packages +```bash +sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ +sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ +sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm +``` +6. Validate whether current cluster is upgradeable +```bash +sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +7. Upgrade Kubernetes cluster to the specified version +```bash +sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +8. Wait for all pods to be running and ready + +9. Reload daemon +```bash +sudo systemctl daemon-reload +``` +10. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +11. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +12. Wait for cluster to be ready, e.g. check: +```bash +kubectl cluster-info +``` +13. Uncordon master - mark as schedulable +```bash +kubectl uncordon $MASTER +``` +14. List all nodes +```bash +kubectl get nodes +# should return $MASTER in status "Ready" and version 1.13.10 +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Important: Worker nodes should be upgraded one by one - this will prevent application downtime. + +##### > RUN ON MASTER + +1. Drain node in preparation for maintenance +```bash +kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] +# $NODE should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +2. Wait for all pods to be running and ready + +##### > RUN ON NODE + +3. Install packages +```bash +sudo apt-mark unhold kubernetes-cni kubelet kubectl kubeadm && \ +sudo apt-get update && sudo apt-get install kubernetes-cni=0.7.5-00 kubelet=1.13.10-00 kubectl=1.13.10-00 kubeadm=1.13.10-00 && \ +sudo apt-mark hold kubernetes-cni kubelet kubectl kubeadm +``` +4. Upgrade node config +```bash +sudo kubeadm upgrade node config --kubelet-version v1.13.10 +``` +5. Reload daemon +```bash +sudo systemctl daemon-reload +``` +6. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +7. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +##### > RUN ON MASTER + +8. Uncordon node - mark as schedulable +```bash +kubectl uncordon $NODE +``` +9. List all nodes +```bash +kubectl get nodes +# should return $NODE in status "Ready" and version 1.13.10 +``` +10. Go back to the point 1 with the next node + + +### RHEL + +#### Upgrade Master + +Variable `$MASTER` represents master node name (node names can be retrieved by command `kubectl get nodes` on master) + +##### > RUN ON MASTER + +1. Check kubeadm version +```bash +kubeadm version +# should show v1.13.1 +``` +2. Find the latest stable 1.13 version +```bash +yum list --showduplicates kubeadm --disableexcludes=kubernetes +# 1.13.10-0 +``` +3. Drain master in preparation for maintenance +```bash +kubectl drain $MASTER # [--ignore-daemonsets] [--delete-local-data] +# $MASTER should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +4. Wait for all pods to be running and ready + +5. Install packages +```bash +sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes +``` +6. Validate whether current cluster is upgradeable +```bash +sudo kubeadm upgrade plan v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +7. Upgrade Kubernetes cluster to the specified version +```bash +sudo kubeadm upgrade apply v1.13.10 # [--config /path/to/kubeadm-config.yml] +``` +8. Wait for all pods to be running and ready + +9. Reload daemon +```bash +sudo systemctl daemon-reload +``` +10. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +11. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +12. Wait for cluster to be ready, e.g. check: +```bash +kubectl cluster-info +``` +13. Uncordon master - mark as schedulable +```bash +kubectl uncordon $MASTER +``` +14. List all nodes +```bash +kubectl get nodes +# should return $MASTER in status "Ready" and version 1.13.10 +``` + +#### Upgrade Worker Nodes + +Commands below should be run in context of each node in the cluster. Variable `$NODE` represents node name (node names can be retrieved by command `kubectl get nodes` on master) + +Important: Worker nodes should be upgraded one by one - this will prevent application downtime. + +##### > RUN ON MASTER + +1. Drain node in preparation for maintenance +```bash +kubectl drain $NODE # [--ignore-daemonsets] [--delete-local-data] +# $NODE should be marked as Ready,SchedulingDisabled +``` +may need to use flags: +```bash +--ignore-daemonsets: # to ignore DaemonSet-managed pods + +--delete-local-data: # to continue even if there are pods using emptyDir (local data that will be deleted when the node is drained) +# BE CAREFUL! +``` +2. Wait for all pods to be running and ready + +##### > RUN ON NODE + +3. Install packages +```bash +sudo yum install kubernetes-cni-0.7.5-0 kubelet-1.13.10-0 kubectl-1.13.10-0 kubeadm-1.13.10-0 --disableexcludes=kubernetes +``` +4. Upgrade node config +```bash +sudo kubeadm upgrade node config --kubelet-version v1.13.10 +``` +5. Reload daemon +```bash +sudo systemctl daemon-reload +``` +6. Restart kubelet +```bash +sudo systemctl restart kubelet +``` +7. Check kubelet status +```bash +sudo systemctl status kubelet +# should be active (running) +``` +##### > RUN ON MASTER + +8. Uncordon node - mark as schedulable +```bash +kubectl uncordon $NODE +``` +9. List all nodes +```bash +kubectl get nodes +# should return $NODE in status "Ready" and version 1.13.10 +``` +10. Go back to the point 1 with the next node + +## How to upgrade Kafka cluster + +### Kafka upgrade + +No downtime upgrades are possible to achieve when upgrading Kafka, but before you start thinking about upgrading you have to think about your topics configuration. Kafka topics are distributed accross partitions with replication. Default value for replication is 3, it means each partition will be replicated to 3 brokers. You should remember to enable redundancy and keep **at least two replicas all the time**, it is important when upgrading Kafka cluser. When one of your Kafka nodes will be down during upgrade ZooKeeper will direct your producers and consumers to working instances - having replicated partitions on working nodes will ensure no downtime and no data loss work. + +Upgrading Kafka could be different for every Kafka release, please refer to [Apache Kafka documentation](https://kafka.apache.org/documentation/#upgrade). Important point to remember during Kafka upgrade is the rule: **only one broker at the time** - to prevent downtime you should uprage you Kafka brokers one by one. + +### ZooKeeper upgrade + +ZooKeeper redundancy is also recommended, since service restart is required during upgrade - it can cause ZooKeeper unavailability. Having at **least two ZooKeeper services** in *ZooKeepers ensemble* you can upgrade one and then start with the rest **one by one**. + +More detailed information about ZooKeeper you can find in [ZooKeeper documentation](https://cwiki.apache.org/confluence/display/ZOOKEEPER). \ No newline at end of file From d6789905aa979983e837efcdd1759c63707dc950 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Mon, 30 Sep 2019 13:44:57 +0200 Subject: [PATCH 43/57] Fixes for SP login. --- .../cli/engine/providers/azure/APIProxy.py | 5 +++- .../cli/engine/terraform/TerraformRunner.py | 30 ++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index 4745851e81..eaa9a00632 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -22,7 +22,7 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def login(self): + def login_account(self): subscription_name = self.cluster_model.specification.cloud.subscription_name all_subscription = self.run(self, 'az login') subscription = select_first(all_subscription, lambda x: x['name'] == subscription_name) @@ -30,6 +30,9 @@ def login(self): raise Exception(f'User does not have access to subscription: "{subscription_name}"') return subscription + def login_sp(self, sp_data): + return self.run(self, f'az login --service-principal -u {sp_data.name} -p {sp_data.password} --tenant {sp_data.tenant}') + def set_active_subscribtion(self, subscription_id): self.run(self, f'az account set --subscription {subscription_id}') diff --git a/core/src/epicli/cli/engine/terraform/TerraformRunner.py b/core/src/epicli/cli/engine/terraform/TerraformRunner.py index 02b1784499..dda24cfa62 100644 --- a/core/src/epicli/cli/engine/terraform/TerraformRunner.py +++ b/core/src/epicli/cli/engine/terraform/TerraformRunner.py @@ -14,6 +14,9 @@ def __init__(self, cluster_model, config_docs): self.config_docs = config_docs self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) self.new_env = os.environ.copy() + self.terraform.init(env=self.new_env) + if self.cluster_model.provider == 'azure': + self.azure_login() def __enter__(self): super().__enter__() @@ -23,14 +26,9 @@ def run(self): pass def build(self): - self.terraform.init(env=self.new_env) - if self.cluster_model.provider == 'azure': - self.azure_login() self.terraform.apply(auto_approve=True, env=self.new_env) def delete(self): - if self.cluster_model.provider == 'azure': - self.azure_login() self.terraform.destroy(auto_approve=True, env=self.new_env) def azure_login(self): @@ -39,12 +37,19 @@ def azure_login(self): # - Authenticating to Azure using the Azure CLI # - Authenticating to Azure using a Service Principal and a Client Secret apiproxy = APIProxy(self.cluster_model, self.config_docs) - subscription = apiproxy.login() - apiproxy.set_active_subscribtion(subscription['id']) - - if self.cluster_model.specification.cloud.use_service_principal: + if not self.cluster_model.specification.cloud.use_service_principal: + # Account + subscription = apiproxy.login_account() + apiproxy.set_active_subscribtion(subscription['id']) + else: + # Service principle sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) if not os.path.exists(sp_file): + # If no service principle exists or is defined we created one and for that we need to login using an account + subscription = apiproxy.login_account() + apiproxy.set_active_subscribtion(subscription['id']) + + # Create the service principle self.logger.info('Creating service principal') cluster_name = self.cluster_model.specification.name.lower() cluster_prefix = self.cluster_model.specification.prefix.lower() @@ -55,8 +60,11 @@ def azure_login(self): self.logger.info('Using service principal from file') sp = load_yaml_file(sp_file) - #Setup environment variables for Terraform when working with Azure and service principal. - self.new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] + # Login as SP. + subscription = apiproxy.login_sp(sp) + + # Setup environment variables for Terraform when working with Azure and service principal. + self.new_env['ARM_SUBSCRIPTION_ID'] = subscription[0]['id'] self.new_env['ARM_TENANT_ID'] = sp['tenant'] self.new_env['ARM_CLIENT_ID'] = sp['appId'] self.new_env['ARM_CLIENT_SECRET'] = sp['password'] From 8dbdfb3061f13e85dbc50a3c2f762b305f82b895 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Mon, 30 Sep 2019 15:07:25 +0200 Subject: [PATCH 44/57] Fixed exit code issue with Ansible. --- .../cli/engine/ansible/AnsibleCommand.py | 10 ++++---- .../cli/engine/ansible/AnsibleRunner.py | 23 ++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py index 6d46fa19d8..d47dfcb2e1 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py @@ -46,8 +46,10 @@ def run_task_with_retries(self, inventory, module, args, hosts, retries, timeout break except Exception as e: self.logger.error(e) - self.logger.info("Retry running task: " + str(i + 1) + "/" + str(retries)) + self.logger.info('Retry running task: ' + str(i + 1) + '/' + str(retries)) time.sleep(timeout) + else: + raise Exception(f'Failed running task after {str(retries)} retries') def run_playbook(self, inventory, playbook_path): cmd = ['ansible-playbook'] @@ -73,13 +75,13 @@ def run_playbook(self, inventory, playbook_path): def run_playbook_with_retries(self, inventory, playbook_path, retries, timeout=10): for i in range(retries): - try: self.run_playbook(inventory=inventory, playbook_path=playbook_path) return 0 except Exception as e: self.logger.error(e) - self.logger.info("Retry running playbook: " + str(i + 1) + "/" + str(retries)) + self.logger.info('Retry running playbook: ' + str(i + 1) + '/' + str(retries)) time.sleep(timeout) - return 1 + else: + raise Exception(f'Failed running playbook after {str(retries)} retries') diff --git a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py index 22b7d03eec..668dfca621 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py @@ -30,6 +30,9 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) self.inventory_creator.__exit__(exc_type, exc_value, traceback) + def playbook_path(self, name): + return os.path.join(get_ansible_path(self.cluster_model.specification.name), f'{name}.yml') + def run(self): inventory_path = get_inventory_path(self.cluster_model.specification.name) @@ -47,21 +50,13 @@ def run(self): self.ansible_vars_generator.run() - common_play_result = self.ansible_command.run_playbook_with_retries(inventory=inventory_path, - playbook_path=os.path.join( - get_ansible_path( - self.cluster_model.specification.name), - "common.yml"), retries=5) - if common_play_result != 0: - return + + self.ansible_command.run_playbook_with_retries(inventory=inventory_path, + playbook_path=self.playbook_path('common'), + retries=5) enabled_roles = self.inventory_creator.get_enabled_roles() for role in enabled_roles: - play_result = self.ansible_command.run_playbook_with_retries(inventory=inventory_path, - playbook_path=os.path.join( - get_ansible_path( - self.cluster_model.specification.name), - to_role_name(role) + ".yml"), retries=1) - if play_result != 0: - break + self.ansible_command.run_playbook(inventory=inventory_path, + playbook_path=self.playbook_path(to_role_name(role))) From 11bb14dfd635615dee3a79e3901dae8244159ab8 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Mon, 30 Sep 2019 15:18:56 +0200 Subject: [PATCH 45/57] Fixed break. --- core/src/epicli/cli/engine/ansible/AnsibleCommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py index d47dfcb2e1..4a76fa8f7b 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py @@ -78,7 +78,7 @@ def run_playbook_with_retries(self, inventory, playbook_path, retries, timeout=1 try: self.run_playbook(inventory=inventory, playbook_path=playbook_path) - return 0 + break except Exception as e: self.logger.error(e) self.logger.info('Retry running playbook: ' + str(i + 1) + '/' + str(retries)) From 0ed57bef7e6ea4b28fe5b36e1abc559a51bc49c0 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Mon, 30 Sep 2019 15:41:15 +0200 Subject: [PATCH 46/57] Preview fixes (#541) - Fixes for SP login. - Fixed exit code issue with Ansible. - Fixed break. --- .../cli/engine/ansible/AnsibleCommand.py | 12 ++++---- .../cli/engine/ansible/AnsibleRunner.py | 23 ++++++-------- .../cli/engine/providers/azure/APIProxy.py | 5 +++- .../cli/engine/terraform/TerraformRunner.py | 30 ++++++++++++------- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py index 6d46fa19d8..4a76fa8f7b 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleCommand.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleCommand.py @@ -46,8 +46,10 @@ def run_task_with_retries(self, inventory, module, args, hosts, retries, timeout break except Exception as e: self.logger.error(e) - self.logger.info("Retry running task: " + str(i + 1) + "/" + str(retries)) + self.logger.info('Retry running task: ' + str(i + 1) + '/' + str(retries)) time.sleep(timeout) + else: + raise Exception(f'Failed running task after {str(retries)} retries') def run_playbook(self, inventory, playbook_path): cmd = ['ansible-playbook'] @@ -73,13 +75,13 @@ def run_playbook(self, inventory, playbook_path): def run_playbook_with_retries(self, inventory, playbook_path, retries, timeout=10): for i in range(retries): - try: self.run_playbook(inventory=inventory, playbook_path=playbook_path) - return 0 + break except Exception as e: self.logger.error(e) - self.logger.info("Retry running playbook: " + str(i + 1) + "/" + str(retries)) + self.logger.info('Retry running playbook: ' + str(i + 1) + '/' + str(retries)) time.sleep(timeout) - return 1 + else: + raise Exception(f'Failed running playbook after {str(retries)} retries') diff --git a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py index 22b7d03eec..668dfca621 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py @@ -30,6 +30,9 @@ def __exit__(self, exc_type, exc_value, traceback): super().__exit__(exc_type, exc_value, traceback) self.inventory_creator.__exit__(exc_type, exc_value, traceback) + def playbook_path(self, name): + return os.path.join(get_ansible_path(self.cluster_model.specification.name), f'{name}.yml') + def run(self): inventory_path = get_inventory_path(self.cluster_model.specification.name) @@ -47,21 +50,13 @@ def run(self): self.ansible_vars_generator.run() - common_play_result = self.ansible_command.run_playbook_with_retries(inventory=inventory_path, - playbook_path=os.path.join( - get_ansible_path( - self.cluster_model.specification.name), - "common.yml"), retries=5) - if common_play_result != 0: - return + + self.ansible_command.run_playbook_with_retries(inventory=inventory_path, + playbook_path=self.playbook_path('common'), + retries=5) enabled_roles = self.inventory_creator.get_enabled_roles() for role in enabled_roles: - play_result = self.ansible_command.run_playbook_with_retries(inventory=inventory_path, - playbook_path=os.path.join( - get_ansible_path( - self.cluster_model.specification.name), - to_role_name(role) + ".yml"), retries=1) - if play_result != 0: - break + self.ansible_command.run_playbook(inventory=inventory_path, + playbook_path=self.playbook_path(to_role_name(role))) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index 4745851e81..eaa9a00632 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -22,7 +22,7 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def login(self): + def login_account(self): subscription_name = self.cluster_model.specification.cloud.subscription_name all_subscription = self.run(self, 'az login') subscription = select_first(all_subscription, lambda x: x['name'] == subscription_name) @@ -30,6 +30,9 @@ def login(self): raise Exception(f'User does not have access to subscription: "{subscription_name}"') return subscription + def login_sp(self, sp_data): + return self.run(self, f'az login --service-principal -u {sp_data.name} -p {sp_data.password} --tenant {sp_data.tenant}') + def set_active_subscribtion(self, subscription_id): self.run(self, f'az account set --subscription {subscription_id}') diff --git a/core/src/epicli/cli/engine/terraform/TerraformRunner.py b/core/src/epicli/cli/engine/terraform/TerraformRunner.py index 02b1784499..dda24cfa62 100644 --- a/core/src/epicli/cli/engine/terraform/TerraformRunner.py +++ b/core/src/epicli/cli/engine/terraform/TerraformRunner.py @@ -14,6 +14,9 @@ def __init__(self, cluster_model, config_docs): self.config_docs = config_docs self.terraform = TerraformCommand(get_terraform_path(self.cluster_model.specification.name)) self.new_env = os.environ.copy() + self.terraform.init(env=self.new_env) + if self.cluster_model.provider == 'azure': + self.azure_login() def __enter__(self): super().__enter__() @@ -23,14 +26,9 @@ def run(self): pass def build(self): - self.terraform.init(env=self.new_env) - if self.cluster_model.provider == 'azure': - self.azure_login() self.terraform.apply(auto_approve=True, env=self.new_env) def delete(self): - if self.cluster_model.provider == 'azure': - self.azure_login() self.terraform.destroy(auto_approve=True, env=self.new_env) def azure_login(self): @@ -39,12 +37,19 @@ def azure_login(self): # - Authenticating to Azure using the Azure CLI # - Authenticating to Azure using a Service Principal and a Client Secret apiproxy = APIProxy(self.cluster_model, self.config_docs) - subscription = apiproxy.login() - apiproxy.set_active_subscribtion(subscription['id']) - - if self.cluster_model.specification.cloud.use_service_principal: + if not self.cluster_model.specification.cloud.use_service_principal: + # Account + subscription = apiproxy.login_account() + apiproxy.set_active_subscribtion(subscription['id']) + else: + # Service principle sp_file = os.path.join(get_terraform_path(self.cluster_model.specification.name), SP_FILE_NAME) if not os.path.exists(sp_file): + # If no service principle exists or is defined we created one and for that we need to login using an account + subscription = apiproxy.login_account() + apiproxy.set_active_subscribtion(subscription['id']) + + # Create the service principle self.logger.info('Creating service principal') cluster_name = self.cluster_model.specification.name.lower() cluster_prefix = self.cluster_model.specification.prefix.lower() @@ -55,8 +60,11 @@ def azure_login(self): self.logger.info('Using service principal from file') sp = load_yaml_file(sp_file) - #Setup environment variables for Terraform when working with Azure and service principal. - self.new_env['ARM_SUBSCRIPTION_ID'] = subscription['id'] + # Login as SP. + subscription = apiproxy.login_sp(sp) + + # Setup environment variables for Terraform when working with Azure and service principal. + self.new_env['ARM_SUBSCRIPTION_ID'] = subscription[0]['id'] self.new_env['ARM_TENANT_ID'] = sp['tenant'] self.new_env['ARM_CLIENT_ID'] = sp['appId'] self.new_env['ARM_CLIENT_SECRET'] = sp['password'] From 7a466d4caedd9d37e3fd1ca81d522ccea847e152 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Tue, 1 Oct 2019 08:21:02 +0200 Subject: [PATCH 47/57] Commit forgotten file. --- core/src/epicli/cli/engine/providers/azure/APIProxy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index eaa9a00632..52f898b370 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -31,7 +31,10 @@ def login_account(self): return subscription def login_sp(self, sp_data): - return self.run(self, f'az login --service-principal -u {sp_data.name} -p {sp_data.password} --tenant {sp_data.tenant}') + name = sp_data['name'] + password = sp_data['password'] + tenant = sp_data['tenant'] + return self.run(self, f'az login --service-principal -u {name} -p {password} --tenant {tenant}') def set_active_subscribtion(self, subscription_id): self.run(self, f'az account set --subscription {subscription_id}') From dd0bc03665453434230d499b4b5c316d57e4a06c Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Tue, 1 Oct 2019 09:17:06 +0200 Subject: [PATCH 48/57] Bumped wait time to fix timeout issue. --- core/src/epicli/cli/engine/providers/azure/APIProxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index 52f898b370..5da839d0f9 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -47,7 +47,7 @@ def create_sp(self, app_name, subscription_id): #TODO: make role configurable? sp = self.run(self, f'az ad sp create-for-rbac -n "{app_name}" --role="Contributor" --scopes="/subscriptions/{subscription_id}"') # Sleep for a while. Sometimes the call returns before the rights of the SP are finished creating. - self.wait(self, 20) + self.wait(self, 60) return sp def get_ips_for_feature(self, component_key): From 5591157eb315c8bf092f85db2b7c3eb303fb1670 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 1 Oct 2019 09:38:44 +0200 Subject: [PATCH 49/57] Added unccommited file. (#542) * Commit forgotten file. --- core/src/epicli/cli/engine/providers/azure/APIProxy.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index eaa9a00632..5da839d0f9 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -31,7 +31,10 @@ def login_account(self): return subscription def login_sp(self, sp_data): - return self.run(self, f'az login --service-principal -u {sp_data.name} -p {sp_data.password} --tenant {sp_data.tenant}') + name = sp_data['name'] + password = sp_data['password'] + tenant = sp_data['tenant'] + return self.run(self, f'az login --service-principal -u {name} -p {password} --tenant {tenant}') def set_active_subscribtion(self, subscription_id): self.run(self, f'az account set --subscription {subscription_id}') @@ -44,7 +47,7 @@ def create_sp(self, app_name, subscription_id): #TODO: make role configurable? sp = self.run(self, f'az ad sp create-for-rbac -n "{app_name}" --role="Contributor" --scopes="/subscriptions/{subscription_id}"') # Sleep for a while. Sometimes the call returns before the rights of the SP are finished creating. - self.wait(self, 20) + self.wait(self, 60) return sp def get_ips_for_feature(self, component_key): From f3812a25fa866a4473d1fcc3b7ff560a42a51481 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij Date: Wed, 2 Oct 2019 13:19:29 +0200 Subject: [PATCH 50/57] Bumped skopeo and fixed issue with empty prefix string. --- core/src/epicli/Pipfile.lock | 108 +++++++++--------- core/src/epicli/cli/helpers/naming_helpers.py | 2 +- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/core/src/epicli/Pipfile.lock b/core/src/epicli/Pipfile.lock index 538fe308e8..21471d292e 100644 --- a/core/src/epicli/Pipfile.lock +++ b/core/src/epicli/Pipfile.lock @@ -25,10 +25,10 @@ }, "ansible": { "hashes": [ - "sha256:a0153e2de3619b7e307df179cd91a3c3804cf1fe048273fe4ea5238b76679ff1" + "sha256:8e9403e755ce8ef27b6066cdd7a4c567aa80ebe2fd90d0ff8efa0a725d246986" ], "index": "pypi", - "version": "==2.8.4" + "version": "==2.8.5" }, "antlr4-python3-runtime": { "hashes": [ @@ -60,10 +60,10 @@ }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2", + "sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396" ], - "version": "==19.1.0" + "version": "==19.2.0" }, "azure-batch": { "hashes": [ @@ -355,10 +355,10 @@ }, "azure-cli-nspkg": { "hashes": [ - "sha256:1bde56090f548c6435bd3093995cf88e4c445fb040604df8b5b5f70780d79181", - "sha256:9a1e4f3197183470e4afecfdd45c92320f6753555b06a70651f89972332ffaf6" + "sha256:1733d195b5b9c79a2d9d02cb1e3e2698103548aac31547961134313bd7af2239", + "sha256:34095c34a04a31868356115f7a2a5eba5e93afb28a35713a713f2ea587b72d2c" ], - "version": "==3.0.4" + "version": "==3.0.3" }, "azure-cli-policyinsights": { "hashes": [ @@ -1010,25 +1010,25 @@ }, "boto3": { "hashes": [ - "sha256:0c4b88af2bf774992cba6361f0af30ca7c7e9fa0dc0f849f241e73edfdeab2b9", - "sha256:97114b6d43c691c7314f461b74da20aaffcc6dc6afaa47ad22b0bc383b112d8a" + "sha256:0895805810df8cc49898fbeb61479c20c63a59fb6d3adf19f78fde90efec10a2", + "sha256:2f174f1e01d898ed940677a66404b7d30cbe92665b1fa2a5086eb64382ce2c41" ], "index": "pypi", - "version": "==1.9.225" + "version": "==1.9.240" }, "botocore": { "hashes": [ - "sha256:e6d17290add0a5e8510af92b26ede437bd618f211bc40ad3e4cdf1e7e478b44c", - "sha256:fe4c216f1d35d0b368d1916d9e8e7f1933deb80d52d8f84a5d2797a810deef5c" + "sha256:040f5307387481501bf2db02dc55c6512553081b43642578687fc47ed8ec990b", + "sha256:7d30b4cc9546a126ccdc9d325a1c02d7f63ff3759b80c9e1f15fd544785e22a1" ], - "version": "==1.12.225" + "version": "==1.12.240" }, "certifi": { "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" ], - "version": "==2019.6.16" + "version": "==2019.9.11" }, "cffi": { "hashes": [ @@ -1221,10 +1221,10 @@ }, "msrestazure": { "hashes": [ - "sha256:070220fa9c86b55026360435b655d1d67ff4306fd1412687c400dc549e9647b7", - "sha256:e9d525b11d88f1073744e128ae19a4e023e4085893cfcfd02483fdd4cee25091" + "sha256:63db9f646fffc9244b332090e679d1e5f283ac491ee0cc321f5116f9450deb4a", + "sha256:fecb6a72a3eb5483e4deff38210d26ae42d3f6d488a7a275bd2423a1a014b22c" ], - "version": "==0.6.1" + "version": "==0.6.2" }, "oauthlib": { "hashes": [ @@ -1410,10 +1410,10 @@ }, "skopeo-bin": { "hashes": [ - "sha256:3686491a2e6251a608e767b6a073736d34c0fce212a23947bdac65d8fd7828d8" + "sha256:dbc64efa7b7c4c1d979e74a6a85537418fb4cd63ebe2326aafe62cfa64015f72" ], "index": "pypi", - "version": "==1.0.2" + "version": "==1.0.3" }, "sshtunnel": { "hashes": [ @@ -1423,9 +1423,9 @@ }, "tabulate": { "hashes": [ - "sha256:8af07a39377cee1103a5c8b3330a421c2d99b9141e9cc5ddd2e3263fea416943" + "sha256:d0097023658d4dea848d6ae73af84532d1e86617ac0925d1adf1dd903985dac3" ], - "version": "==0.8.3" + "version": "==0.8.5" }, "terraform-bin": { "hashes": [ @@ -1439,11 +1439,11 @@ "secure" ], "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", + "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" ], "markers": "python_version >= '3.4'", - "version": "==1.25.3" + "version": "==1.25.6" }, "vsts": { "hashes": [ @@ -1497,10 +1497,10 @@ }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2", + "sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396" ], - "version": "==19.1.0" + "version": "==19.2.0" }, "bleach": { "hashes": [ @@ -1511,10 +1511,10 @@ }, "certifi": { "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" ], - "version": "==2019.6.16" + "version": "==2019.9.11" }, "chardet": { "hashes": [ @@ -1540,11 +1540,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:9ff1b1c5a354142de080b8a4e9803e5d0d59283c93aed808617c787d16768375", - "sha256:b7143592e374e50584564794fcb8aaf00a23025f9db866627f89a21491847a8d" + "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", + "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af" ], "markers": "python_version < '3.8'", - "version": "==0.20" + "version": "==0.23" }, "more-itertools": { "hashes": [ @@ -1555,10 +1555,10 @@ }, "packaging": { "hashes": [ - "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", - "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" + "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", + "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108" ], - "version": "==19.1" + "version": "==19.2" }, "pkginfo": { "hashes": [ @@ -1569,10 +1569,10 @@ }, "pluggy": { "hashes": [ - "sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", - "sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c" + "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", + "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" ], - "version": "==0.12.0" + "version": "==0.13.0" }, "py": { "hashes": [ @@ -1597,11 +1597,11 @@ }, "pytest": { "hashes": [ - "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", - "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" + "sha256:13c1c9b22127a77fc684eee24791efafcef343335d855e3573791c68588fe1a5", + "sha256:d8ba7be9466f55ef96ba203fc0f90d0cf212f2f927e69186e1353e30bc7f62e5" ], "index": "pypi", - "version": "==5.1.2" + "version": "==5.2.0" }, "readme-renderer": { "hashes": [ @@ -1633,29 +1633,29 @@ }, "tqdm": { "hashes": [ - "sha256:1be3e4e3198f2d0e47b928e9d9a8ec1b63525db29095cec1467f4c5a4ea8ebf9", - "sha256:7e39a30e3d34a7a6539378e39d7490326253b7ee354878a92255656dc4284457" + "sha256:abc25d0ce2397d070ef07d8c7e706aede7920da163c64997585d42d3537ece3d", + "sha256:dd3fcca8488bb1d416aa7469d2f277902f26260c45aa86b667b074cd44b3b115" ], - "version": "==4.35.0" + "version": "==4.36.1" }, "twine": { "hashes": [ - "sha256:b2cec0dc1ac55bd74280d257f43763cf0cf928bdcd0de0fd70be70aa1195e3b0", - "sha256:e37d5a73d77b095b85314dde807bfb85b580b5b9d137f5b21332f4636990d97a" + "sha256:5319dd3e02ac73fcddcd94f035b9631589ab5d23e1f4699d57365199d85261e1", + "sha256:9fe7091715c7576df166df8ef6654e61bada39571783f2fd415bdcba867c6993" ], "index": "pypi", - "version": "==1.14.0" + "version": "==2.0.0" }, "urllib3": { "extras": [ "secure" ], "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", + "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" ], "markers": "python_version >= '3.4'", - "version": "==1.25.3" + "version": "==1.25.6" }, "wcwidth": { "hashes": [ diff --git a/core/src/epicli/cli/helpers/naming_helpers.py b/core/src/epicli/cli/helpers/naming_helpers.py index 8052e1207a..11c2f28b3a 100644 --- a/core/src/epicli/cli/helpers/naming_helpers.py +++ b/core/src/epicli/cli/helpers/naming_helpers.py @@ -8,7 +8,7 @@ def to_feature_name(role_name): def resource_name(prefix, cluster_name, resource_type, component=None): name = '' - if prefix == 'default': + if (not prefix) or (prefix == 'default'): if component is None: name = '%s-%s' % (cluster_name.lower(), resource_type.lower()) else: From a5f136e7e365cd5a77967316d6f6cc4532e4b183 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 2 Oct 2019 15:23:49 +0200 Subject: [PATCH 51/57] Added rabbitmq and postgresql tests to epicli (#543) --- .../kubernetes_master_spec.rb | 2 +- .../spec/postgresql/postgresql_spec.rb | 268 ++++++++++++++++++ .../spec/rabbitmq/rabbitmq_spec.rb | 162 +++++++++++ .../tests/serverspec-cli/spec/spec_helper.rb | 26 +- 4 files changed, 453 insertions(+), 5 deletions(-) create mode 100644 core/src/epicli/tests/serverspec-cli/spec/postgresql/postgresql_spec.rb create mode 100644 core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb diff --git a/core/src/epicli/tests/serverspec-cli/spec/kubernetes_master/kubernetes_master_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/kubernetes_master/kubernetes_master_spec.rb index 977eadfc2c..33d8d6f3ca 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/kubernetes_master/kubernetes_master_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/kubernetes_master/kubernetes_master_spec.rb @@ -29,7 +29,7 @@ end describe 'Waiting for all pods to be ready' do - describe command("for i in {1..600}; do if [ $(kubectl get pods --all-namespaces -o json | jq -r '.items[] | select(.status.phase != \"Running\" or ([ .status.conditions[] | select(.type == \"Ready\" and .status != \"True\") ] | length ) == 1 ) | .metadata.namespace + \"/\" + .metadata.name' | wc -l) -eq 0 ]; \ + describe command("for i in {1..1200}; do if [ $(kubectl get pods --all-namespaces -o json | jq -r '.items[] | select(.status.phase != \"Running\" or ([ .status.conditions[] | select(.type == \"Ready\" and .status != \"True\") ] | length ) == 1 ) | .metadata.namespace + \"/\" + .metadata.name' | wc -l) -eq 0 ]; \ then echo 'READY'; break; else echo 'WAITING'; sleep 1; fi; done") do its(:stdout) { should match /READY/ } its(:exit_status) { should eq 0 } diff --git a/core/src/epicli/tests/serverspec-cli/spec/postgresql/postgresql_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/postgresql/postgresql_spec.rb new file mode 100644 index 0000000000..05ee6524ef --- /dev/null +++ b/core/src/epicli/tests/serverspec-cli/spec/postgresql/postgresql_spec.rb @@ -0,0 +1,268 @@ +require 'spec_helper' +require 'net/ssh' + +postgresql_default_port = 5432 +replicated = readDataYaml("configuration/postgresql")["specification"]["replication"]["enable"] +replication_user = readDataYaml("configuration/postgresql")["specification"]["replication"]["user"] +replication_password = readDataYaml("configuration/postgresql")["specification"]["replication"]["password"] +max_wal_senders = readDataYaml("configuration/postgresql")["specification"]["replication"]["max_wal_senders"] +wal_keep_segments = readDataYaml("configuration/postgresql")["specification"]["replication"]["wal_keep_segments"] + + +def queryForCreating + describe 'Checking if it is possible to create a test schema' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'CREATE SCHEMA serverspec_test;'\"") do + its(:stdout) { should match /^CREATE SCHEMA$/ } + its(:exit_status) { should eq 0 } + end + end + + describe 'Checking if it is possible to create a test table' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'CREATE TABLE serverspec_test.test (col varchar(20));'\"") do + its(:stdout) { should match /^CREATE TABLE$/ } + its(:exit_status) { should eq 0 } + end + end + + describe 'Checking if it is possible to insert values into the test table' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c \\\"INSERT INTO serverspec_test.test (col) values ('SUCCESS');\\\"\"") do + its(:stdout) { should match /^INSERT 0 1$/ } + its(:exit_status) { should eq 0 } + end + end +end + +def queryForSelecting + describe 'Checking if it is possible to select values from the test table' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'SELECT * from serverspec_test.test;'\"") do + its(:stdout) { should match /\bSUCCESS\b/ } + its(:exit_status) { should eq 0 } + end + end +end + +def queryForDropping + describe 'Checking if it is possible to drop the test table' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'DROP TABLE serverspec_test.test;'\"") do + its(:stdout) { should match /^DROP TABLE$/ } + its(:exit_status) { should eq 0 } + end + end + + describe 'Checking if it is possible to drop the test schema' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'DROP SCHEMA serverspec_test;'\"") do + its(:stdout) { should match /^DROP SCHEMA$/ } + its(:exit_status) { should eq 0 } + end + end +end + +describe 'Checking if PostgreSQL service is running' do + describe service('postgresql') do + it { should be_enabled } + it { should be_running } + end +end + +if os[:family] == 'redhat' + describe 'Checking PostgreSQL directories and config files' do + let(:disable_sudo) { false } + describe file('/var/opt/rh/rh-postgresql10/lib/pgsql/data') do + it { should exist } + it { should be_a_directory } + end + describe file("/var/opt/rh/rh-postgresql10/lib/pgsql/data/pg_hba.conf") do + it { should exist } + it { should be_a_file } + it { should be_readable } + end + describe file("/var/opt/rh/rh-postgresql10/lib/pgsql/data/postgresql.conf") do + it { should exist } + it { should be_a_file } + it { should be_readable } + end + end +elsif os[:family] == 'ubuntu' + describe 'Checking PostgreSQL directories and config files' do + let(:disable_sudo) { false } + describe file('/etc/postgresql/10/main') do + it { should exist } + it { should be_a_directory } + end + describe file("/etc/postgresql/10/main/pg_hba.conf") do + it { should exist } + it { should be_a_file } + it { should be_readable } + end + describe file("/etc/postgresql/10/main/postgresql.conf") do + it { should exist } + it { should be_a_file } + it { should be_readable } + end + end +end + +describe 'Checking if the ports are open' do + let(:disable_sudo) { false } + describe port(postgresql_default_port) do + it { should be_listening } + end +end + +describe 'Checking if PostgreSQL is ready' do + describe command("pg_isready") do + its(:stdout) { should match /postgresql:#{postgresql_default_port} - accepting connections/ } + its(:exit_status) { should eq 0 } + end +end + +describe 'Checking if it is possible to connect to PostgreSQL database' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'SELECT 2+2;'\"") do + its(:stdout) { should match /4/ } + its(:exit_status) { should eq 0 } + end +end + +if !replicated + queryForCreating + queryForSelecting + queryForDropping +end + +if replicated + nodes = listInventoryHosts("postgresql") + master = nodes[0] + master_ip = listInventoryIPs("postgresql")[0] + slave = nodes[1] + + if master.include? host_inventory['hostname'] + if os[:family] == 'redhat' + describe 'Checking PostgreSQL config files for master' do + let(:disable_sudo) { false } + describe command("cat /var/opt/rh/rh-postgresql10/lib/pgsql/data/postgresql.conf | grep wal_level") do + its(:stdout) { should match /^wal_level = replica/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /var/opt/rh/rh-postgresql10/lib/pgsql/data/postgresql.conf | grep max_wal_senders") do + its(:stdout) { should match /^max_wal_senders = #{max_wal_senders}/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /var/opt/rh/rh-postgresql10/lib/pgsql/data/postgresql.conf | grep wal_keep_segments") do + its(:stdout) { should match /^wal_keep_segments = #{wal_keep_segments}/ } + its(:exit_status) { should eq 0 } + end + describe command("su - postgres -c \"psql -t -c '\\du'\" | grep #{replication_user}") do + its(:stdout) { should match /#{replication_user}/ } + its(:stdout) { should match /Replication/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /var/opt/rh/rh-postgresql10/lib/pgsql/data/pg_hba.conf | grep replication | grep md5") do + its(:stdout) { should match /#{replication_user}/ } + its(:stdout) { should match /replication/ } + its(:exit_status) { should eq 0 } + end + end + elsif os[:family] == 'ubuntu' + describe 'Checking PostgreSQL config files for master' do + let(:disable_sudo) { false } + describe command("cat /etc/postgresql/10/main/postgresql.conf | grep wal_level") do + its(:stdout) { should match /^wal_level = replica/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /etc/postgresql/10/main/postgresql.conf | grep max_wal_senders") do + its(:stdout) { should match /^max_wal_senders = #{max_wal_senders}/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /etc/postgresql/10/main/postgresql.conf | grep wal_keep_segments") do + its(:stdout) { should match /^wal_keep_segments = #{wal_keep_segments}/ } + its(:exit_status) { should eq 0 } + end + describe command("su - postgres -c \"psql -t -c '\\du'\" | grep #{replication_user}") do + its(:stdout) { should match /#{replication_user}/ } + its(:stdout) { should match /Replication/ } + its(:exit_status) { should eq 0 } + end + describe command("cat /etc/postgresql/10/main/pg_hba.conf | grep replication | grep md5") do + its(:stdout) { should match /#{replication_user}/ } + its(:stdout) { should match /replication/ } + its(:exit_status) { should eq 0 } + end + end + end + + describe 'Checking the status of master node' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'SELECT usename, state from pg_stat_replication;'\"") do + its(:stdout) { should match /\bstreaming\b/ } + its(:stdout) { should match /\b#{replication_user}\b/ } + its(:exit_status) { should eq 0 } + end + end + + queryForCreating + queryForSelecting + + elsif slave.include? host_inventory['hostname'] + if os[:family] == 'redhat' + describe 'Checking PostgreSQL config files for slave' do + let(:disable_sudo) { false } + describe command("cat /var/opt/rh/rh-postgresql10/lib/pgsql/data/postgresql.conf | grep hot_standby") do + its(:stdout) { should match /^hot_standby = on/ } + its(:exit_status) { should eq 0 } + end + describe file('/var/lib/pgsql/.pgpass') do + it { should exist } + it { should be_readable } + its(:content) { should match /#{replication_user}:#{replication_password}/ } + end + end + elsif os[:family] == 'ubuntu' + describe 'Checking PostgreSQL config files for slave' do + let(:disable_sudo) { false } + describe command("cat /etc/postgresql/10/main/postgresql.conf | grep hot_standby") do + its(:stdout) { should match /^hot_standby = on/ } + its(:exit_status) { should eq 0 } + end + describe file('/var/lib/postgresql/.pgpass') do + it { should exist } + it { should be_readable } + its(:content) { should match /#{replication_user}:#{replication_password}/ } + end + end + end + + describe 'Checking the state of replica nodes' do + let(:disable_sudo) { false } + describe command("su - postgres -c \"psql -t -c 'SELECT status, conninfo from pg_stat_wal_receiver;'\"") do + its(:stdout) { should match /\bstreaming\b/ } + its(:stdout) { should match /\buser=#{replication_user}\b/ } + its(:exit_status) { should eq 0 } + end + end + + queryForSelecting + + describe 'Clean up' do + it "Delegate drop table query to master" do + Net::SSH.start(master_ip, ENV['user'], keys: [ENV['keypath']], :keys_only => TRUE) do|ssh| + result = ssh.exec!("sudo su - postgres -c \"psql -t -c 'DROP TABLE serverspec_test.test;'\"") + expect(result).to match 'DROP TABLE' + end + end + it "Delegate drop schema query to master" do + Net::SSH.start(master_ip, ENV['user'], keys: [ENV['keypath']], :keys_only => TRUE) do|ssh| + result = ssh.exec!("sudo su - postgres -c \"psql -t -c 'DROP SCHEMA serverspec_test;'\"") + expect(result).to match 'DROP SCHEMA' + end + end + end + + end +end diff --git a/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb new file mode 100644 index 0000000000..07ad797f7f --- /dev/null +++ b/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb @@ -0,0 +1,162 @@ +require 'spec_helper' +require 'securerandom' + +rabbitmq_host = 'localhost' +rabbitmq_port = readDataYaml("configuration/rabbitmq")["specification"]["amqp_port"] +rabbitmq_node_port = rabbitmq_port + 20000 +rabbitmq_api_port = 15672 +clustered = readDataYaml("configuration/rabbitmq")["specification"]["cluster"]["is_clustered"] +user = 'testuser' + SecureRandom.hex(5) +pass = SecureRandom.hex + +describe 'Checking if RabbitMQ package is installed' do + describe package('rabbitmq-server') do + it { should be_installed } + end +end + +describe 'Checking if RabbitMQ user exists' do + describe group('rabbitmq') do + it { should exist } + end + describe user('rabbitmq') do + it { should exist } + it { should belong_to_group 'rabbitmq' } + end +end + +describe 'Checking if RabbitMQ service is running' do + describe service('rabbitmq-server') do + it { should be_enabled } + it { should be_running } + end +end + +describe 'Checking if the ports are open' do + let(:disable_sudo) { false } + describe port(rabbitmq_port) do + it { should be_listening } + end + describe port(rabbitmq_node_port) do + it { should be_listening } + end +end + +describe 'Checking RabbitMQ ping' do + describe command("rabbitmqctl ping") do + let(:disable_sudo) { false } + its(:stdout) { should match /^Ping succeeded$/ } + its(:exit_status) { should eq 0 } + end +end + +describe 'Checking the health of the target nodes' do + let(:disable_sudo) { false } + if clustered == true + listInventoryHosts("rabbitmq").each do |val| + describe command("rabbitmqctl node_health_check -n rabbit@#{val}") do + its(:stdout) { should match /^Health check passed$/ } + its(:exit_status) { should eq 0 } + end + end + else + describe command("rabbitmqctl node_health_check -n rabbit@#{host_inventory['hostname']}") do + its(:stdout) { should match /^Health check passed$/ } + its(:exit_status) { should eq 0 } + end + end +end + +describe 'Checking the RabbitMQ status/cluster status' do + let(:disable_sudo) { false } + describe command("rabbitmqctl status") do + its(:exit_status) { should eq 0 } + end + if clustered + listInventoryHosts("rabbitmq").each do |val| + describe command("rabbitmqctl cluster_status | awk '/running_nodes/,/}/'") do + its(:stdout) { should match /rabbit@#{val}/ } + its(:exit_status) { should eq 0 } + end + end + else + describe command("rabbitmqctl cluster_status | awk '/running_nodes/,/}/'") do + its(:stdout) { should match /rabbit@#{host_inventory['hostname']}/ } + its(:exit_status) { should eq 0 } + end + end +end + +describe 'Checking if it is possible to create the test user' do + describe command("rabbitmqctl add_user #{user} #{pass} && rabbitmqctl set_user_tags #{user} administrator \ + && rabbitmqctl set_permissions -p / #{user} \".*\" \".*\" \".*\"") do + let(:disable_sudo) { false } + its(:stdout) { should match /Adding user "#{user}"/ } + its(:stdout) { should match /Setting tags for user "#{user}" to \[administrator\]/ } + its(:stdout) { should match /Setting permissions for user "#{user}"/ } + its(:exit_status) { should eq 0 } + end +end + +# Tests to be run only when RabbitMQ plugins section is enabled + +plugins = readDataYaml("configuration/rabbitmq")["specification"]["rabbitmq_plugins"] + +describe 'Checking if RabbitMQ plugins are enabled' do + plugins.each do |val| + describe command("rabbitmq-plugins list -e") do + let(:disable_sudo) { false } + its(:stdout) { should match /\b#{val}\b/ } + its(:exit_status) { should eq 0 } + end + end +end + +# Tests to be run only when RabbitMQ Management Plugin is enabled + +if plugins.include? "rabbitmq_management" + + describe 'Checking if the port for RabbitMQ Management Plugin is open' do + let(:disable_sudo) { false } + describe port(rabbitmq_api_port) do + it { should be_listening } + end + end + + describe 'Checking nodes health using RabbitMQ API' do + let(:disable_sudo) { false } + if clustered + listInventoryHosts("rabbitmq").each do |val| + describe command("curl -o /dev/null -s -w '%{http_code}' -u #{user}:#{pass} #{rabbitmq_host}:#{rabbitmq_api_port}/api/healthchecks/node/rabbit@#{val}") do + it "is expected to be equal" do + expect(subject.stdout.to_i).to eq 200 + end + end + describe command("curl -u #{user}:#{pass} #{rabbitmq_host}:#{rabbitmq_api_port}/api/healthchecks/node/rabbit@#{val}") do + its(:stdout_as_json) { should include('status' => /ok/) } + its(:stdout_as_json) { should_not include('status' => /failed/) } + its(:exit_status) { should eq 0 } + end + end + else + describe command("curl -o /dev/null -s -w '%{http_code}' -u #{user}:#{pass} #{rabbitmq_host}:#{rabbitmq_api_port}/api/healthchecks/node/rabbit@#{host_inventory['hostname']}") do + it "is expected to be equal" do + expect(subject.stdout.to_i).to eq 200 + end + end + describe command("curl -u #{user}:#{pass} #{rabbitmq_host}:#{rabbitmq_api_port}/api/aliveness-test/%2F") do + its(:stdout_as_json) { should include('status' => /ok/) } + its(:stdout_as_json) { should_not include('status' => /failed/) } + its(:exit_status) { should eq 0 } + end + end + end +end + +describe 'Cleaning up' do + describe command("rabbitmqctl delete_user #{user}") do + let(:disable_sudo) { false } + its(:stdout) { should match /Deleting user "#{user}"/ } + its(:exit_status) { should eq 0 } + end +end diff --git a/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb b/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb index 99d0262889..0d15dc128e 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb @@ -62,11 +62,14 @@ def hostInGroups?(role) end end - def readDataYaml + def readDataYaml(kind) path = ENV['inventory'].dup path.sub! 'inventory' , 'manifest.yml' - datayaml = YAML.load_file(path) - return datayaml + datayaml = [] + YAML.load_stream(File.read path) do |ruby| + datayaml << ruby + end + return datayaml.select {|x| x["kind"] == kind }[0] end def listInventoryHosts(role) @@ -83,5 +86,20 @@ def listInventoryHosts(role) end end return list - end + end + def listInventoryIPs(role) + file = File.open(ENV['inventory'], "rb") + input = file.read + file.close + list = [] + if input.include? "[#{role}]" + rows = input.split("[#{role}]")[1].split("[")[0] + rows.each_line do |line| + if line[0] != '#' and line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ + list << line.split('=').last.strip + end + end + end + return list + end From 93aa4df6d25bb6843c6b4634ce23e00bffed8444 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 4 Oct 2019 20:38:31 +0200 Subject: [PATCH 52/57] Fixed naming issues and added conventions (#553) * Fixed naming issues and added conventions: - validator fixes - prefix field validation - cluster name field validation - cluster tag fixes * Minor update for storage account naming and tests. --- .../cli/engine/providers/azure/APIProxy.py | 4 +- .../providers/azure/InfrastructureBuilder.py | 6 +-- .../cli/engine/schema/SchemaValidator.py | 16 +++++-- core/src/epicli/cli/helpers/naming_helpers.py | 35 ++++++++++++++ .../data/common/defaults/epiphany-cluster.yml | 2 +- .../common/validation/epiphany-cluster.yml | 44 ++++++++++++++++- .../azure/test_AzureConfigBuilder.py | 2 +- .../tests/cli/helpers/test_name_helpers.py | 48 ++++++++++++++++++- 8 files changed, 143 insertions(+), 14 deletions(-) diff --git a/core/src/epicli/cli/engine/providers/azure/APIProxy.py b/core/src/epicli/cli/engine/providers/azure/APIProxy.py index 5da839d0f9..528697dd31 100644 --- a/core/src/epicli/cli/engine/providers/azure/APIProxy.py +++ b/core/src/epicli/cli/engine/providers/azure/APIProxy.py @@ -4,7 +4,7 @@ from subprocess import Popen, PIPE from cli.helpers.Log import LogPipe, Log from cli.helpers.doc_list_helpers import select_first -from cli.helpers.naming_helpers import resource_name +from cli.helpers.naming_helpers import resource_name, cluster_tag from cli.models.AnsibleHostModel import AnsibleHostModel class APIProxy: @@ -52,7 +52,7 @@ def create_sp(self, app_name, subscription_id): def get_ips_for_feature(self, component_key): look_for_public_ip = self.cluster_model.specification.cloud.use_public_ips - cluster = f'{self.cluster_prefix}-{self.cluster_name}' + cluster = cluster_tag(self.cluster_prefix, self.cluster_name) running_instances = self.run(self, f'az vm list-ip-addresses --ids $(az resource list --query "[?type==\'Microsoft.Compute/virtualMachines\' && tags.{component_key} == \'\' && tags.cluster == \'{cluster}\'].id" --output tsv)') result = [] for instance in running_instances: diff --git a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py index 54e5c880df..3afdc4c2bd 100644 --- a/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py +++ b/core/src/epicli/cli/engine/providers/azure/InfrastructureBuilder.py @@ -3,7 +3,7 @@ from copy import deepcopy from cli.helpers.Step import Step -from cli.helpers.naming_helpers import resource_name +from cli.helpers.naming_helpers import resource_name, cluster_tag, storage_account_name from cli.helpers.doc_list_helpers import select_single, select_all from cli.helpers.doc_list_helpers import select_first from cli.helpers.data_loader import load_yaml_obj, types @@ -148,7 +148,7 @@ def get_public_ip(self, component_key, component_value, vm_config, index): def get_storage_share_config(self): storage_share = self.get_config_or_default(self.docs, 'infrastructure/storage-share') storage_share.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'k8s-ss') - storage_share.specification.storage_account_name = self.cluster_prefix + self.cluster_name + 'k8s' + storage_share.specification.storage_account_name = storage_account_name(self.cluster_prefix, self.cluster_name, 'k8s') return storage_share def get_vm(self, component_key, component_value, vm_config, network_interface_name, index): @@ -156,7 +156,7 @@ def get_vm(self, component_key, component_value, vm_config, network_interface_na vm.specification.name = resource_name(self.cluster_prefix, self.cluster_name, 'vm' + '-' + str(index), component_key) vm.specification.admin_username = self.cluster_model.specification.admin_user.name vm.specification.network_interface_name = network_interface_name - vm.specification.tags.append({'cluster': f'{self.cluster_prefix}-{self.cluster_name}'}) + vm.specification.tags.append({'cluster': cluster_tag(self.cluster_prefix, self.cluster_name)}) vm.specification.tags.append({component_key: ''}) if vm.specification.os_type == 'linux': # For linux we dont need a PW since we only support SSH. We add something random for Terraform diff --git a/core/src/epicli/cli/engine/schema/SchemaValidator.py b/core/src/epicli/cli/engine/schema/SchemaValidator.py index 6e9854645e..2d1e40906d 100644 --- a/core/src/epicli/cli/engine/schema/SchemaValidator.py +++ b/core/src/epicli/cli/engine/schema/SchemaValidator.py @@ -34,10 +34,16 @@ def get_base_schema(self, kind): def run(self): for doc in self.validation_docs: - self.logger.info('Validating: ' + doc.kind) + self.logger.info(f'Validating: {doc.kind}') schema = self.get_base_schema(doc.kind) - schema['specification'] = load_yaml_obj(types.VALIDATION, self.cluster_model.provider, doc.kind) - if schema["specification"]['$ref'] == '#/definitions/unvalidated_specification': - self.logger.warn('No specification validation for ' + doc.kind) - validate(instance=objdict_to_dict(doc), schema=objdict_to_dict(schema)) + schema['properties']['specification'] = load_yaml_obj(types.VALIDATION, self.cluster_model.provider, doc.kind) + if hasattr(schema['properties']["specification"], '$ref'): + if schema['properties']["specification"]['$ref'] == '#/definitions/unvalidated_specification': + self.logger.warn('No specification validation for ' + doc.kind) + try: + validate(instance=objdict_to_dict(doc), schema=objdict_to_dict(schema)) + except Exception as e: + self.logger.error(f'Failed validating: {doc.kind}') + self.logger.error(e) + raise Exception('Schema validation error, see the error above.') diff --git a/core/src/epicli/cli/helpers/naming_helpers.py b/core/src/epicli/cli/helpers/naming_helpers.py index 11c2f28b3a..688afda2df 100644 --- a/core/src/epicli/cli/helpers/naming_helpers.py +++ b/core/src/epicli/cli/helpers/naming_helpers.py @@ -1,3 +1,6 @@ +import random +import string + def to_role_name(feature_name): return feature_name.replace("-", "_") @@ -19,3 +22,35 @@ def resource_name(prefix, cluster_name, resource_type, component=None): else: name = '%s-%s-%s-%s' % (prefix.lower(), cluster_name.lower(), component.lower(), resource_type.lower()) return to_feature_name(name) + + +def cluster_tag(prefix, cluster_name): + if (not prefix) or (prefix == 'default'): + return cluster_name.lower() + else: + return '%s-%s' % (prefix.lower(), cluster_name.lower()) + + +def storage_account_name(prefix, cluster_name, storage_use): + pre = '' + if not ((not prefix) or (prefix == 'default')): + if len(prefix) > 8: + pre = prefix[:8].lower() + else: + pre = prefix.lower() + + sto = '' + if len(storage_use) > 5: + sto = storage_use[:5].lower() + else: + sto = storage_use.lower() + + clu = '' + length = 24 - (len(pre)+len(sto)) + if len(cluster_name) > length: + clu = cluster_name[:length].lower() + else: + clu = cluster_name.lower() + + return f'{pre}{clu}{sto}' + diff --git a/core/src/epicli/data/common/defaults/epiphany-cluster.yml b/core/src/epicli/data/common/defaults/epiphany-cluster.yml index 30370436dd..fb0d4bb217 100644 --- a/core/src/epicli/data/common/defaults/epiphany-cluster.yml +++ b/core/src/epicli/data/common/defaults/epiphany-cluster.yml @@ -4,8 +4,8 @@ title: "Epiphany cluster Config" provider: aws name: "default" specification: - name: EpiphanyCluster prefix: default + name: epiphanycluster admin_user: name: operations # YOUR-ADMIN-USERNAME key_path: /root/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH diff --git a/core/src/epicli/data/common/validation/epiphany-cluster.yml b/core/src/epicli/data/common/validation/epiphany-cluster.yml index 0f26bd2946..25537a58d5 100644 --- a/core/src/epicli/data/common/validation/epiphany-cluster.yml +++ b/core/src/epicli/data/common/validation/epiphany-cluster.yml @@ -1 +1,43 @@ -$ref: '#/definitions/empty_specification' \ No newline at end of file +"$id": "#/epiphany-cluster/specification" +title: "Cluster specification schema" +description: "The main cluster specification" +type: object +required: + - name + - admin_user + - components +properties: + prefix: + "$id": "#/epiphany-cluster/properties/prefix" + title: "Cluster prefix" + description: "A prefix the can be prepended to the cluster name" + examples: + - prod01 + - dev02 + - test03 + - cust04 + type: string + pattern: "^[a-z0-9]{2,8}$" + name: + "$id": "#/epiphany-cluster/properties/name" + title: "Cluster name" + description: "The name of the cluster" + examples: + - clustername01 + type: string + pattern: "^[a-z0-9]{3,20}$" + admin_user: + "$id": "#/epiphany-cluster/properties/admin_user" + title: "The admin_user Schema" + description: "Settings needed for the SSH connection to the cluster machines or VM's" + type: object + cloud: + "$id": "#/epiphany-cluster/properties/cloud" + title: "Cloud Schema" + description: "Settings specific to cloud providers (AWS, Azure)" + type: object + components: + "$id": "#/epiphany-cluster/properties/components" + title: "Components schema" + description: "Cluster component layout specification" + type: object \ No newline at end of file diff --git a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py index 1129cc232e..7ed23a7002 100644 --- a/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py +++ b/core/src/epicli/tests/cli/engine/providers/azure/test_AzureConfigBuilder.py @@ -113,7 +113,7 @@ def test_get_storage_share_config_should_set_proper_values_to_model(): actual = builder.get_storage_share_config() assert actual.specification.name == 'prefix-testcluster-k8s-ss' - assert actual.specification.storage_account_name == 'prefixtestclusterk8s' + assert actual.specification.storage_account_name == 'prefixtestclusterk8s' assert actual.specification.quota == 50 diff --git a/core/src/epicli/tests/cli/helpers/test_name_helpers.py b/core/src/epicli/tests/cli/helpers/test_name_helpers.py index 33fe6c6ac7..614acf4ea9 100644 --- a/core/src/epicli/tests/cli/helpers/test_name_helpers.py +++ b/core/src/epicli/tests/cli/helpers/test_name_helpers.py @@ -1,4 +1,4 @@ -from cli.helpers.naming_helpers import to_role_name, to_feature_name, resource_name +from cli.helpers.naming_helpers import to_role_name, to_feature_name, resource_name, cluster_tag, storage_account_name def test_to_role_name(): @@ -30,3 +30,49 @@ def test_resource_name_pr_cn_rt_cmp(): actual = resource_name('prefix', 'Cluster', 'Type', component='Component') assert actual == "prefix-cluster-component-type" + +def test_cluster_tag_no_prefix1(): + actual = cluster_tag('default', 'Cluster') + assert actual == "cluster" + + +def test_cluster_tag_no_prefix2(): + actual = cluster_tag('', 'Cluster') + assert actual == "cluster" + + +def test_cluster_tag_no_prefix3(): + actual = cluster_tag(None, 'Cluster') + assert actual == "cluster" + + +def test_cluster_tag(): + actual = cluster_tag('prefix', 'Cluster') + assert actual == "prefix-cluster" + + +def test_storage_account_name_no_prefix1(): + actual = storage_account_name('default', 'Cluster', 'use') + assert actual == "clusteruse" + + +def test_storage_account_name_no_prefix2(): + actual = storage_account_name('', 'Cluster', 'use') + assert actual == "clusteruse" + + +def test_storage_account_name_no_prefix3(): + actual = storage_account_name(None, 'Cluster', 'use') + assert actual == "clusteruse" + + +def test_storage_account_short(): + actual = storage_account_name('Prefix', 'Cluster', 'Use') + assert actual == "prefixclusteruse" + + +def test_storage_account_long(): + actual = storage_account_name('Prefix', 'SuperLongClusterName', 'SuperLongUse') + assert len(actual) == 24 + assert actual == "prefixsuperlongclussuper" + From 7b984feb5c74ad41706049a34876da56453e1587 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Tue, 8 Oct 2019 16:16:01 +0200 Subject: [PATCH 53/57] Fix/aws ports and naming (#576) * FIxes: - Init issues for different providers - Link in docs * Added ports for clustering Postgres and RabbitMQ --- .../configuration/minimal-cluster-config.yml | 2 +- .../configuration/minimal-cluster-config.yml | 4 +-- .../infrastructure/virtual-machine.yml | 30 +++++++++++++++++++ .../configuration/minimal-cluster-config.yml | 4 +-- docs/home/HOWTO.md | 2 +- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml index d301058a7d..dfe7ad50f4 100644 --- a/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/any/defaults/configuration/minimal-cluster-config.yml @@ -4,7 +4,7 @@ title: "Epiphany cluster Config" provider: any name: "default" specification: - name: YOUR_CLUSTER_NAME + name: name admin_user: name: operations # YOUR-ADMIN-USERNAME key_path: /user/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH diff --git a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml index 28b3526024..1a06ed15ed 100644 --- a/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/aws/defaults/configuration/minimal-cluster-config.yml @@ -4,8 +4,8 @@ title: "Epiphany cluster Config" provider: aws name: "default" specification: - name: YOUR_CLUSTER_NAME - prefix: YOUR_CLUSTER_RESOURCES_PREFIX + name: name + prefix: prefix admin_user: name: operations # YOUR-ADMIN-USERNAME key_path: /user/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index 3f88d7aca7..ea28c68cbb 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -138,6 +138,26 @@ specification: destination_port_range: "5672" source_address_prefix: "10.1.0.0/20" destination_address_prefix: "0.0.0.0/0" + - name: rabbitmq_clustering_1 + description: Allow rabbitmq clustering traffic 1 + priority: 304 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "4369" + source_address_prefix: "10.1.8.0/24" + destination_address_prefix: "0.0.0.0/0" + - name: rabbitmq_clustering_1 + description: Allow rabbitmq clustering traffic 2 + priority: 305 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "25672" + source_address_prefix: "10.1.8.0/24" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 @@ -619,6 +639,16 @@ specification: destination_port_range: "0" source_address_prefix: "10.1.2.0/24" destination_address_prefix: "0.0.0.0/0" + - name: postgres_clustering + description: Allow Postgres clustering traffic + priority: 305 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "5432" + source_address_prefix: "10.1.6.0/24" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.4.0 diff --git a/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml index 13b5dcc993..fc09003f52 100644 --- a/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml +++ b/core/src/epicli/data/azure/defaults/configuration/minimal-cluster-config.yml @@ -4,8 +4,8 @@ title: "Epiphany cluster Config" provider: azure name: "default" specification: - name: YOUR_CLUSTER_NAME - prefix: YOUR_CLUSTER_RESOURCES_PREFIX + name: name + prefix: prefix admin_user: name: operations # YOUR-ADMIN-USERNAME key_path: /user/.ssh/epiphany-operations/id_rsa # YOUR-SSH-KEY-PATH diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index 2880ecab32..df218d5db1 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -15,7 +15,7 @@ - [Epiphany cluster](./howto/CLUSTER.md) - Epicli - [How to create an Epiphany cluster on existing infrastructure](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-existing-infrastructure) - - [How to create an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-create-an-epiphany-on-a-cloud-provider) + - [How to create an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-a-cloud-provider) - [How to delete an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-delete-an-epiphany-cluster-on-a-cloud-provider) - [How to create an offline installation of for Epiphany cluster](./howto/CLUSTER.md#how-to-create-an-offline-installation-for-an-Epiphany-cluster) - [Single machine cluster](./howto/CLUSTER.md#single-machine-cluster) From f551be1233ce496e0b2576357a64227626622c9a Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Wed, 9 Oct 2019 13:36:30 +0200 Subject: [PATCH 54/57] RabbitMQ test fix for AWS hostnames (#578) --- .../tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb b/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb index 07ad797f7f..35469dc54e 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/rabbitmq/rabbitmq_spec.rb @@ -54,6 +54,7 @@ let(:disable_sudo) { false } if clustered == true listInventoryHosts("rabbitmq").each do |val| + val = val.split(".")[0] describe command("rabbitmqctl node_health_check -n rabbit@#{val}") do its(:stdout) { should match /^Health check passed$/ } its(:exit_status) { should eq 0 } @@ -74,6 +75,7 @@ end if clustered listInventoryHosts("rabbitmq").each do |val| + val = val.split(".")[0] describe command("rabbitmqctl cluster_status | awk '/running_nodes/,/}/'") do its(:stdout) { should match /rabbit@#{val}/ } its(:exit_status) { should eq 0 } @@ -127,6 +129,7 @@ let(:disable_sudo) { false } if clustered listInventoryHosts("rabbitmq").each do |val| + val = val.split(".")[0] describe command("curl -o /dev/null -s -w '%{http_code}' -u #{user}:#{pass} #{rabbitmq_host}:#{rabbitmq_api_port}/api/healthchecks/node/rabbit@#{val}") do it "is expected to be equal" do expect(subject.stdout.to_i).to eq 200 @@ -159,4 +162,4 @@ its(:stdout) { should match /Deleting user "#{user}"/ } its(:exit_status) { should eq 0 } end -end +end \ No newline at end of file From c5b2743b724026eea0bbf91221fa82607a6db738 Mon Sep 17 00:00:00 2001 From: przemyslawdy <43173646+przemyslawdy@users.noreply.github.com> Date: Thu, 10 Oct 2019 16:59:19 +0200 Subject: [PATCH 55/57] Test fix - added regexp to eliminate false negatives in particular cases (#586) --- core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb b/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb index 0d15dc128e..03c841071b 100644 --- a/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb +++ b/core/src/epicli/tests/serverspec-cli/spec/spec_helper.rb @@ -57,7 +57,7 @@ def hostInGroups?(role) file.close if input.include? "[#{role}]" rows = input.split("[#{role}]")[1].split("[")[0] - return rows.include? ENV['TARGET_HOST'] + return rows =~ /\b#{ENV['TARGET_HOST']}\b/ else return false end end From ab173f8eceb96ba9e45494e1c7d2f8273986a98b Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 11 Oct 2019 15:13:31 +0200 Subject: [PATCH 56/57] Feature/doc updates (#584) * - Updated changelog * Added article for up/downscaling, clustering components. * Added article for offline installation. --- CHANGELOG-0.4.md | 4 +- docs/home/HOWTO.md | 4 +- docs/home/howto/CLUSTER.md | 145 +++++++++++++++++++++++++++++++++++-- 3 files changed, 142 insertions(+), 11 deletions(-) diff --git a/CHANGELOG-0.4.md b/CHANGELOG-0.4.md index f1f32af93a..6bfb41f44d 100644 --- a/CHANGELOG-0.4.md +++ b/CHANGELOG-0.4.md @@ -1,6 +1,6 @@ # Changelog 0.4 -## [0.4.0] 2019-09-30 +## [0.4.0] 2019-10-11 ### Added @@ -19,6 +19,8 @@ - [#407](https://github.com/epiphany-platform/epiphany/issues/407) - Deployment/Application role fails because Kubernetes cluster is not ready after reboot. - [#410](https://github.com/epiphany-platform/epiphany/issues/410) - Node_exporter ports are not present in defaults resulting in Prometheus not beeing able to scrape data with minimal cluster data.yaml. +- [#548](https://github.com/epiphany-platform/epiphany/issues/548) - Epicli fails on AWS when clustering RabbitMQ nodes. +- [#549](https://github.com/epiphany-platform/epiphany/issues/549) - Need to allow traffic on port 5432 to enable PostgreSQL replication on AWS. ### Known issues diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index df218d5db1..0b68afdf00 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -15,11 +15,11 @@ - [Epiphany cluster](./howto/CLUSTER.md) - Epicli - [How to create an Epiphany cluster on existing infrastructure](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-existing-infrastructure) + - [How to create an Epiphany cluster on existing airgapped infrastructure](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-existing-airgapped-infrastructure) - [How to create an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-create-an-epiphany-cluster-on-a-cloud-provider) - [How to delete an Epiphany cluster on a cloud provider](./howto/CLUSTER.md#how-to-delete-an-epiphany-cluster-on-a-cloud-provider) - - [How to create an offline installation of for Epiphany cluster](./howto/CLUSTER.md#how-to-create-an-offline-installation-for-an-Epiphany-cluster) - [Single machine cluster](./howto/CLUSTER.md#single-machine-cluster) - - [How to scale components](./howto/CLUSTER.md#how-to-scale-components) + - [How to scale or cluster components](./howto/CLUSTER.md#how-to-scale-or-cluster-components) - Legacy - [How to create an Epiphany legacy cluster on premise](./howto/CLUSTER.md#how-to-create-an-epiphany-legacy-cluster-on-premise) - [How to create an Epiphany legacy cluster on Azure](./howto/CLUSTER.md#how-to-create-an-epiphany-legacy-cluster-on-azure) diff --git a/docs/home/howto/CLUSTER.md b/docs/home/howto/CLUSTER.md index 8e3a5fd23c..666cb42d53 100644 --- a/docs/home/howto/CLUSTER.md +++ b/docs/home/howto/CLUSTER.md @@ -6,13 +6,13 @@ Epicli has the ability to setup a cluster on infrastructure provided by you. The *Note. Hardware requirements are not listed since this dependends on use-case, component configuration etc.* -1. All the machines are connected by a network or virtual network of some sorts and can communicate which each other. -2. Running one of the following Linux distributions: +1. The cluster machines/vm`s are connected by a network or virtual network of some sorts and can communicate which each other and have access to the internet. +2. The cluster machines/vm`s are running one of the following Linux distributions: - Redhat 7.4+ - CentOS 7.4+ - Ubuntu 18.04 Other distributions/version might work but are un-tested. -3. All machines should be accessible through SSH with a set of SSH keys you provide and configure on each machine yourself. +3. The cluster machines/vm`s are should be accessible through SSH with a set of SSH keys you provide and configure on each machine yourself. 4. A provisioning machine that: - Has access to the SSH keys - Is on the same network as your cluster machines @@ -72,6 +72,101 @@ To setup the cluster do the following steps from the provisioning machine: This will create the inventory for Ansible based on the component/machine definitions made inside the `newcluster.yml` and let Absible deploy it. Note that the `--no-infra` is important since it tells Epicli to skip the Terraform part. +### How to create an Epiphany cluster on existing airgapped infrastructure + +Epicli has the ability to setup a cluster on airgapped infrastructure provided by you. These can be either bare metal machines or VM's and should meet the following requirements: + +*Note. Hardware requirements are not listed since this dependends on use-case, component configuration etc.* + +1. The airgapped cluster machines/vm`s are connected by a network or virtual network of some sorts and can communicate which each other: +2. The airgapped cluster machines/vm`s are running one of the following Linux distributions: + - Redhat 7.4+ + - CentOS 7.4+ + - Ubuntu 18.04 + Other distributions/version might work but are un-tested. +3. The airgapped cluster machines/vm`s should be accessible through SSH with a set of SSH keys you provide and configure on each machine yourself. +2. A requirements machine that: + - Runs the same distribution as the airgapped cluster machines/vm`s (Redhat 7.4+, CentOS 7.4+, Ubuntu 18.04) + - Has access to the internet. +3. A provisioning machine that: + - Has access to the SSH keys + - Is on the same network as your cluster machines + - Has Epicli running. + *Note. To run Epicli check the [Prerequisites](./PREREQUISITES.md)* + +To setup the cluster do the following steps: + +1. First we need to get the tooling to prepare the requirements. On the provisioning machine run: + + ```shell + epicli prepare --os OS + ``` + + Where OS should be `centos-7`, `redhat-7`, `ubuntu-18.04`. This will create a directory called `prepare_scripts` with the following files inside: + + - download-requirements.sh + - requirements.txt + - skopeo_linux + +2. The scripts in the `prepare_scripts` will be used to download all requirements. To do that copy the `prepare_scripts` folder over to the requirements machine and run the following command: + + ```shell + download-requirements.sh /requirementsoutput/ + ``` + + This will start downloading all requirements and put them in the `/requirementsoutput/` folder. Once run succesfully the `/requirementsoutput/` needs to be copied to the provisioning machine to be used later on. + +3. Then generate a minimal data yaml file on the provisioning machine: + + ```shell + epicli init -p any -n newcluster + ``` + + The `any` provider will tell Epicli to create a minimal data config which does not contain any cloud provider related information. If you want full control you can add the `--full` flag which will give you a configuration with all parts of a cluster that can be configured. + +4. Open the configuration file and setup the `admin_user` data: + + ```yaml + admin_user: + key_path: /path/to/your/ssh/keys + name: user_name + ``` + Here you should specify the path to the SSH keys and the admin user name which will be used by Anisble to provision the cluster machines. + +5. Define the components you want to install and link them to the machines you want to install them on: + + Under the `components` tag you will find a bunch of definitions like this one: + + ```yaml + kubernetes_master: + count: 1 + machines: + - default-k8s-master + ``` + + The `count` specifies how much machines you want to provision with this component. The `machines` tag is the array of machine names you want to install this component on. Note that the `count` and the number of `machines` defined must match. If you don't want to use a component you can set the `count` to 0 and remove the `machines` tag. Finally a machine can be used by multiple component since multiple components can be installed on one machine of desired. + + You will also find a bunch of `infrastructure/machine` definitions like below: + + ```yaml + kind: infrastructure/machine + name: default-k8s-master + provider: any + specification: + hostname: master + ip: 192.168.100.101 + ``` + + Each machine name used when setting up the component layout earlier must have such a configuration where the `name` tag matches with the defined one in the components. The `hostname` and `ip` fields must be filled to match the actual cluster machines you provide. Ansible will use this to match the machine to a component which in turn will determin which roles to install on the machine. + +6. Finally start the deployment with: + + ```shell + epicli apply -f newcluster.yml --no-infra --offline-requirements /requirementsoutput/ + ``` + + This will create the inventory for Ansible based on the component/machine definitions made inside the `newcluster.yml` and let Absible deploy it. Note that the `--no-infra` is important since it tells Epicli to skip the Terraform part. The `--offline-requirements` tells Epicli it is an airgapped installation and to use the `/requirementsoutput/` requirements folder prepared in steps 1 and 2 as source for all requirements. + ### How to create an Epiphany cluster on a cloud provider Epicli has the ability to setup a cluster on one of the following cloud providers: @@ -189,17 +284,51 @@ Epicli has a delete command to remove a cluster from a cloud provider (AWS, Azur From the defined cluster build folder it will take the information needed to remove the resources from the cloud provider. -### How to create an offline installation for an Epiphany cluster +### Single machine cluster TODO -### Single machine cluster +### How to scale or cluster components -TODO +Epiphany has the ability to automaticly scale and cluster certain components on cloud providers (AWS, Azure). To upscale or downscale a component the `count` number must be increased or decreased: -### How to scale components + ```yaml + components: + kubernetes_node: + count: ... + ... + ``` -TODO +Then when applying the changed configuration using Epicli additional VM's will be spawned and configured or removed. The following components support scaling/clustering: + +- kubernetes_node: When changed this will setup or remove additional nodes with `kubernetes_master`. +- kafka: When changed this will setup or remove additional nodes for the Kafka cluster. +- rabbitmq: When changed this will setup or remove additional nodes for the RabbitMQ cluster. Note that this will require to enable clustering in the `configuration/rabbitmq` configuration: + + ```yaml + kind: configuration/rabbitmq + ... + specification: + cluster: + is_clustered: true + ... + ``` +- postgresql: When changed this will setup or remove additional nodes for Postgresql. Note that extra nodes can only be setup todo replication by adding the following additional `configuration/postgresql` configuration: + + ```yaml + kind: configuration/postgresql + ... + specification: + replication: + enable: true + user: postgresql-replication-user + password: postgresql-replication-password + max_wal_senders: 5 + wal_keep_segments: 32 + ... + ``` + +Changing the count for other predefined components will spawn additional machines or remove VM's ## Legacy From 43a1e500c05429de86d59f5257fbe699959dc1a0 Mon Sep 17 00:00:00 2001 From: Luuk van Venrooij <11056665+seriva@users.noreply.github.com> Date: Fri, 11 Oct 2019 17:27:16 +0200 Subject: [PATCH 57/57] Merge offline into develop. (#603) * Added download role * Kubernetes install packages, dependencies list added * Loading images from download cache- Kubernetes role * Docker installation from offline * Added download role * Commit to store prototype (temporary changes) * Updated prototype * sync -> copy + improvements * The same package for multiple OS distros handled * Grafana offline mode install, docker offline fixes * ELK, HAProxy, Postgresql moved to offline installation * RabbitMQ package installation offline mode * HAProxy experimental binary install (offline mode) * RabbitMQ offline, HAProxy offline binary install (#473) * RabbitMQ package installation offline mode * HAProxy experimental binary install (offline mode) * Added links to kibana, haproxy, filebeat, elasticsearch, grafana, docker packages (#474) * Added links to haproxy_exporter and rabbitmq packages (#476) * Offline mode for (file install): elacticsearch-curator, haproxy_exporter, jmx_exporter, kafka, node_exporter * Fixes for downloading packages and installing Docker on Ubuntu (#480) * Updated variable names for dest dirs * Fixes for downloading packages * Prometheus, AlertManager and ZooKeeper move to offline mode * Tasks for downloading all files and improvements (#412) * Added links to postgresql, zookeeper, kafka, prometheus, exporter packages (#484) * Exact version match (#485) * Exact version match (#412) * Simplified setting properties (#412) * Fix: Prevent docs duplication in manifest * Remote_src fix in unarchive, haproxy and haproxy_exporter validated * [Offline-mode] ELK stack updated * Fixes for offline mode with packages and files * Kubernetes installation of deb package fix * Download all packages + fix for admin_user (#504) * Feature/offline-mode - added image download capability (#486) * image download capability added * multiple fixes and multi-arch support added * Added links to Kubernetes packages (#502) * Removing the test environment destruction function * Added links to kibana, haproxy, filebeat, elasticsearch, grafana, docker packages * Added links to haproxy_exporter and rabbitmq packages * Added links to haproxy_exporter and rabbitmq packages * Added links to postgresql packages * Added links to postgresql packages * Added links to postgresql packages * Added links to zookeeper, kafka, exporter packages * Added links to Kubernetes packages * replaced sha512 with file_name * More fixes to offline mode (#503) * Fix: Prevent docs duplication in manifest * Remote_src fix in unarchive, haproxy and haproxy_exporter validated * [Offline-mode] ELK stack updated * Fixes for offline mode with packages and files * Kubernetes installation of deb package fix * Removed test data (#412) (#505) * Feature/offline-mode - image download tweaks, added configuration example (#507) * change url to full docker registry path with version tag, added configuration examples * removal of unnecessary quotations, silenced ansible warning * Kafka, Kafka exporter, postgresql and install role * Add offline-mode flag to epicli * Add offline mode to AnsibleVarsGenerator * Add offline flag for epicli (#510) * Add offline-mode flag to epicli * Add offline mode to AnsibleVarsGenerator * Installing packages + files + images using artifacts repository * Installing packages + files + images using artifacts repository (#512) * Rewrote: postgress, haproxy and haproxy_exporter. * Prometheus, Grafana, Exporters, Kafka, Zookeeper to use private repo * Kafka exporter moved to private repo * Rewrote: postgress, haproxy and haproxy_exporter. (#514) * Missing flannel image definition in K8s configuration * Download role cleanup * Install role cleanup * Add stub of repositories role * Fixed feature mapping yaml * Updated elk, Kibana, Filebeat, elk-curator. * Added file_name for haproxy-exporter * Roles to use private repo (#515) * Installing packages + files + images using artifacts repository * Prometheus, Grafana, Exporters, Kafka, Zookeeper to use private repo * Kafka exporter moved to private repo * Missing flannel image definition in K8s configuration * Download role cleanup * Install role cleanup * Fixed feature mapping yaml * Feature/offline mode (#516) - Updated elk, Kibana, Filebeat, elk-curator - Added file_name for haproxy-exporter * Add setup and teardown to Epiphany role * Add integration to repository role with epicli * Change repository configuration to take files from kubernetes master server * Fixed remove of node_exporter endpoint accessibility on kubernetes master for default configuration * Add offline/online mode for Red Hat (#519) * Added prepare command to prepare offline repo scripts. * - Updated RabbitMQ roll to pull stuff from repo. * Add scopeo copying (#521) * Add offline/online mode for Red Hat * Add skopeo copy and stub of task for Debian * Copy scopeo to upload dir * Add new structure of files to repository role (#522) * Add offline/online mode for Red Hat * Add skopeo copy and stub of task for Debian * Copy scopeo to upload dir * Changed repository script structure * Move repository scripts * Add directories copy for new data structure * Fixes for Red Hat script * Refactor of repository role. * Refactored stuff. * download-requirements.sh for CentOS-7 (#513) (#526) download-requirements.sh for CentOS-7 * Started refactoring repository role. (#527) * Refactor of repository role. * Refactored stuff. * Run download-requirements.sh from any location (#528) Run download-requirements.sh from any location * Move Skopeo for copying to repo host and add message for long running repo task. * Feature/offline mode (#529) - Move Skopeo for copying to repo host and add message for long running repo task. * Offline progress - Changed offline_mode to offline_requirements accepting a path param. - Removed old offline mode code - Removed useless checks for AnsibleVarsGenerator.py * Minor message update. * Feature/offline mode (#530) - Changed offline_mode to offline_requirements accepting a path param. - Removed old offline mode code - Removed useless checks for AnsibleVarsGenerator.py * Offline progress - Fix for local epi-repo path. - Cleaned up old code. * Feature/offline mode (#531) - Fix for local epi-repo path. - Cleaned up old code. * Refactoring repository role (#532) - Refactoring repository role * Changes in repository role (#533) * Redirect STDERR to STDOUT for logging * Fix for packages containing 'error' in name * Added Perl as dependency for vim * Fix for 'ERROR 403: Forbidden' on AWS * Added python-firewall for firewalld * Added dependencies for vim * - Minor fixes after merge with develop * Fixed version numbers. * More dependencies for vim (#538) * Merged develop into feature/offline + some fixes (#539) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * Feature/skopeo (#475) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * - Added Skopeo minor update to devcontainer. * subnets, network interfaces, security rules, ansible inventory (#469) Fixes for subnets Fixed versions for Terraform providers for both Azure and AWS Added VMs Added network interfaces Added security rules Added ansible inventory generation * File generating hashes for directory (#477) * Item: #422 Desc: Add missing ports for prometheus and grafana * Item: #0000 Desc: File hash generator for directory * Item: #0000 Desc: Moved folder to new structure * Testruns (#506) - Added running of python unit tests via debug config in VSCode - Added running of serverspec tests via debug config in VSCode - Documentation * Release prep part 1 (#501) * Updated documentation - Added changelog - Added versions to for components - Minor documentation updates - Removed unused documentation * Fixed links. * Fixed changelog. * Added node_exporter port known issue. * Preparation for release. * Feature/azure-k8n-storage (#487) - Added shared storage for k8n * Azure rehat fixes (#511) Fix for container-selinux package on redhat. Fixes for HAProxy and Posgress on Azure. Fix for running tests from VSCode. * Fix typo rabbitmq (#518) * Fix/rabbitmq error (#523) - Fixed typo for rabbitmq machine * Fixed link to container-selinux package (legacy) (#525) * Fixed link to container-selinux package * Refactor of repository role. * Refactored stuff. * Move Skopeo for copying to repo host and add message for long running repo task. * Offline progress - Changed offline_mode to offline_requirements accepting a path param. - Removed old offline mode code - Removed useless checks for AnsibleVarsGenerator.py * Minor message update. * Offline progress - Fix for local epi-repo path. - Cleaned up old code. * - Minor fixes after merge with develop * Fixed version numbers. * Debian scripts for download * Reverted temp changes * Review changes * Changed scripts fore Debian packages (#540) * Installing packages + files + images using artifacts repository * Prometheus, Grafana, Exporters, Kafka, Zookeeper to use private repo * Kafka exporter moved to private repo * Missing flannel image definition in K8s configuration * Download role cleanup * Install role cleanup * Fix for dependencies to be downloaded (#544) * uniq -> 'sort --unique' * Updated package dependencies * Remove trailing spaces * java-1.8.0-openjdk -> java-1.8.0-openjdk-headless * Refactored repository role, changes for RHEL (#547) * Refactored repository role, changes for RHEL #536 * Changed directories structure for tasks #536 * Added repository role to feature mappings #536 * Fix for removing flag file if expired #536 * Added wget #536 * Minor fix for prepare when output dir is not supplied. * Minor fix for prepare paths (#550) - Minor fix for prepare when output dir is not supplied. * Offline mode - progress for RedHat (#552) * Added --log-to-journal option #536 * download-requirements script logs to journal #536 * Added python-slip-dbus for firewalld on AWS #536 * Disabled repository role in feature mappings #536 * Static version for docker-ce #536 * download-reqs: yum makecache fast -> yum makecache #536 * Do not install epel-release #536 * Download latest versions of dependencies #536 * Optimizations and better naming #536 * Colons -> hyphens in file names of images #536 * jmx_prometheus_javaagent v0.12.0 #536 * Better task names in zookeeper role * Offline mode progress (#555) * yum makecache -> yum makecache fast #536 * Added versions for docker-ce & docker-ce-cli #536 * Added property 'download_done_flag_expire_minutes' #536 * enabled-system-repos.txt in /var/tmp #536 * Clean up temporary files #536 * Added execution time #536 * Fixes for Azure in repository role #536 * Fixes for centos offline mode * Fixes for offline centos (#577) * Installing packages + files + images using artifacts repository * Prometheus, Grafana, Exporters, Kafka, Zookeeper to use private repo * Kafka exporter moved to private repo * Missing flannel image definition in K8s configuration * Download role cleanup * Install role cleanup * Fixed feature mapping yaml * Debian scripts for download * Reverted temp changes * Review changes * Fixes for centos offline mode * Fixes for offline mode for RedHat after testing (#579) * Improvements after testing #536 * Rabbitmq and Erlang in fixed version #536 * Added --cacheonly to yum repolist #536 * Removed old structure #536 * Local docker registry for controlplane images * Change comment for custom_image_registry Co-Authored-By: to-bar <46519524+to-bar@users.noreply.github.com> * Skip downloading when image exists #536 * Fix in repository teardown #536 * Missing coredns images, flannel installation fix * WIP: Feature/offline Ubuntu part (#580) * offline repo for ubuntu - merge scripts into repository role - initial support * requirements and repo creation fixes * ubuntu offline-online installation works * apt-cache policy not needed here * cleanups * added missing bash error handling * added removal of 3rd party repos, other cleanups, install wget and gpg for minimal OS * fix for running script from different location (#583) * Fixes for offline mode for RedHat and CentOS (#585) * Fix for hosts without yum-utils package #536 * Fixes for repo prereqs and image permissions #536 * Offline mode Ubuntu part - fixes (#587) * fix for running script from different location * fixed skopeo .tar permissions to 644 * added missing dependencies for jq * Fix/offline ubu (#588) * fix for running script from different location * fixed skopeo .tar permissions to 644 * added missing dependencies for jq * bootstrap apache and dpkg-dev installation in air-gap mode * Requirements and repo creation for centos * Added missing file * Requirements and repo creation for centos (#589) * Requirements and repo creation for centos * Added missing file * Added NSG rules for image repository and package repository * Added security rules to AWS and fixed on Azure * Added security rules to AWS and fixed on Azure (#591) * Offline mode Ubuntu part - fixes for air-gap mode, install libdpkg-perl (#592) * fixes for air-gap mode, install libdpkg-perl * unified stderr to stdout bash pipe with rhel version of this script * convoluted comments are convoluted * added missing dependencies * Change name for RedHat filebeat * File name typo fix (#593) * Changed name to fix again... * Fixed name for RedHat in rabbitmq tasks. * Epicli validation and RabbitMQ and Postgress cluster fixes. (#595) * Ensure httpd is running * Ensure httpd is running (#597) * Ensure httpd is running * Added killing of the previous instance for Ansible * Set up sysctl params for K8s * Fix/offline ubu (#599) * fixes for air-gap mode, install libdpkg-perl * unified stderr to stdout bash pipe with rhel version of this script * convoluted comments are convoluted * added missing dependencies * added dependencies for postgresql-10 and gpg/gnupg * Fixed default HAProxy config * Fix/offline last minute improvements (#601) * fixes for air-gap mode, install libdpkg-perl * unified stderr to stdout bash pipe with rhel version of this script * convoluted comments are convoluted * added missing dependencies * added dependencies for postgresql-10 and gpg/gnupg * restore system repos if missing, logging improvements * Fix in enable-system-repos.sh for RHEL (#604) * Merged develop into offline. (#605) * Fix/aws ports and naming (#576) * FIxes: - Init issues for different providers - Link in docs * Added ports for clustering Postgres and RabbitMQ * RabbitMQ test fix for AWS hostnames (#578) * Test fix - added regexp to eliminate false negatives in particular cases (#586) * Feature/doc updates (#584) * - Updated changelog * Added article for up/downscaling, clustering components. * Added article for offline installation. * removal of unneeded code from Ubuntu 16.04 era (#606) --- core/src/epicli/.gitignore | 2 +- core/src/epicli/cli/engine/BuildEngine.py | 4 +- core/src/epicli/cli/engine/PrepareEngine.py | 53 ++ .../cli/engine/ansible/AnsibleRunner.py | 24 +- .../engine/ansible/AnsibleVarsGenerator.py | 18 +- .../engine/schema/ConfigurationAppender.py | 23 +- core/src/epicli/cli/epicli.py | 25 + core/src/epicli/cli/helpers/Config.py | 22 +- .../infrastructure/virtual-machine.yml | 32 +- .../infrastructure/virtual-machine.yml | 20 + .../common/ansible/playbooks/download.yml | 8 + .../ansible/playbooks/elasticsearch.yml | 3 + .../playbooks/elasticsearch_curator.yml | 3 + .../common/ansible/playbooks/filebeat.yml | 4 + .../data/common/ansible/playbooks/grafana.yml | 3 + .../ansible/playbooks/group_vars/all.yml | 5 + .../data/common/ansible/playbooks/haproxy.yml | 4 +- .../ansible/playbooks/haproxy_exporter.yml | 4 +- .../ansible/playbooks/image_registry.yml | 12 + .../common/ansible/playbooks/jmx_exporter.yml | 4 + .../data/common/ansible/playbooks/kafka.yml | 4 + .../ansible/playbooks/kafka_exporter.yml | 4 + .../data/common/ansible/playbooks/kibana.yml | 4 + .../ansible/playbooks/kubernetes_master.yml | 4 + .../ansible/playbooks/node_exporter.yml | 3 + .../common/ansible/playbooks/postgresql.yml | 3 + .../common/ansible/playbooks/prometheus.yml | 4 + .../common/ansible/playbooks/repository.yml | 5 + .../ansible/playbooks/repository_setup.yml | 10 + .../ansible/playbooks/repository_teardown.yml | 10 + .../playbooks/roles/common/tasks/Debian.yml | 6 +- .../playbooks/roles/common/tasks/RedHat.yml | 12 +- .../playbooks/roles/common/tasks/main.yml | 37 - .../playbooks/roles/docker/defaults/main.yml | 2 + .../playbooks/roles/docker/tasks/Debian.yml | 26 - .../playbooks/roles/docker/tasks/RedHat.yml | 28 - .../playbooks/roles/docker/tasks/main.yml | 21 +- .../roles/docker/templates/daemon.json.j2 | 5 + .../roles/download/tasks/download_file.yml | 12 + .../roles/download/tasks/download_image.yml | 12 + .../playbooks/roles/download/tasks/main.yml | 3 + .../roles/elasticsearch/tasks/Debian.yml | 38 +- .../roles/elasticsearch/tasks/RedHat.yml | 37 +- .../roles/elasticsearch/tasks/main.yml | 21 +- .../elasticsearch_curator/tasks/Debian.yml | 13 +- .../elasticsearch_curator/tasks/RedHat.yml | 10 +- .../elasticsearch_curator/tasks/main.yml | 2 +- .../playbooks/roles/filebeat/tasks/Debian.yml | 11 +- .../playbooks/roles/filebeat/tasks/RedHat.yml | 11 +- .../playbooks/roles/filebeat/tasks/main.yml | 4 +- .../playbooks/roles/grafana/tasks/install.yml | 71 +- .../playbooks/roles/grafana/tasks/main.yml | 14 - .../grafana/templates/grafana_rh.repo.j2 | 10 - .../playbooks/roles/grafana/vars/debian.yml | 8 - .../playbooks/roles/grafana/vars/redhat.yml | 3 - .../playbooks/roles/haproxy/tasks/RedHat.yml | 25 - .../roles/haproxy_exporter/tasks/main.yml | 69 +- .../roles/image_registry/meta/main.yml | 3 + .../roles/image_registry/tasks/main.yml | 32 + .../roles/jmx_exporter/tasks/main.yml | 42 +- .../playbooks/roles/kafka/tasks/main.yml | 4 +- .../roles/kafka/tasks/setup-kafka.yml | 115 ++-- .../roles/kafka_exporter/tasks/main.yml | 70 +- .../playbooks/roles/kibana/tasks/Debian.yml | 44 +- .../playbooks/roles/kibana/tasks/RedHat.yml | 48 +- .../playbooks/roles/kibana/tasks/main.yml | 33 +- .../tasks/install-packages-Debian.yml | 15 +- .../tasks/install-packages-RedHat.yml | 19 +- .../kubernetes_common/tasks/load-image.yml | 35 + .../roles/kubernetes_common/tasks/main.yml | 32 + .../tasks/cni-plugins/calico.yml | 10 +- .../tasks/cni-plugins/flannel.yml | 8 +- .../kubernetes_master/tasks/single-master.yml | 20 +- .../calico.yml => templates/calico.yml.j2} | 10 +- .../templates/canal-deployment.yml.j2 | 8 +- .../coredns-config.yml.j2} | 2 +- .../kube-flannel.yml.j2} | 20 +- .../templates/kubeadm-config.yml.j2 | 9 +- .../kubernetes-dashboard.yml.j2} | 4 +- .../roles/node_exporter/tasks/main.yml | 67 +- .../roles/postgresql/tasks/Debian.yml | 2 +- .../roles/postgresql/tasks/RedHat.yml | 26 - .../playbooks/roles/postgresql/tasks/main.yml | 1 - .../prometheus/tasks/install-alertmanager.yml | 67 +- .../roles/prometheus/tasks/install.yml | 173 +++-- .../roles/prometheus/tasks/preflight.yml | 4 +- .../playbooks/roles/rabbitmq/tasks/Debian.yml | 27 +- .../playbooks/roles/rabbitmq/tasks/RedHat.yml | 19 +- .../files/client/Debian/add-epirepo-client.sh | 7 + .../create-enabled-system-repos-list.sh | 7 + .../client/Debian/disable-epirepo-client.sh | 5 + .../client/Debian/disable-system-repos.sh | 9 + .../client/Debian/enable-system-repos.sh | 5 + .../files/client/RedHat/add-epirepo-client.sh | 19 + .../create-enabled-system-repos-list.sh | 8 + .../client/RedHat/disable-epirepo-client.sh | 5 + .../client/RedHat/disable-system-repos.sh | 16 + .../client/RedHat/enable-system-repos.sh | 22 + .../centos-7/download-requirements.sh | 611 +++++++++++++++++ .../centos-7/requirements.txt | 138 ++++ .../redhat-7/download-requirements.sh | 634 ++++++++++++++++++ .../redhat-7/requirements.txt | 134 ++++ .../ubuntu-18.04/add-repositories.sh | 22 + .../ubuntu-18.04/common.sh | 81 +++ .../ubuntu-18.04/download-requirements.sh | 153 +++++ .../ubuntu-18.04/requirements.txt | 144 ++++ .../files/server/Debian/create-repository.sh | 27 + .../Debian/disable-repository-server.sh | 4 + .../files/server/Debian/dpkg-scanpackages | 295 ++++++++ .../files/server/RedHat/create-repository.sh | 20 + .../RedHat/disable-repository-server.sh | 4 + .../roles/repository/tasks/Debian/setup.yml | 23 + .../repository/tasks/Debian/teardown.yml | 12 + .../roles/repository/tasks/RedHat/setup.yml | 33 + .../repository/tasks/RedHat/teardown.yml | 12 + .../tasks/download-requirements.yml | 37 + .../roles/repository/tasks/setup.yml | 76 +++ .../roles/repository/tasks/teardown.yml | 11 + .../roles/zookeeper/defaults/main.yml | 5 - .../playbooks/roles/zookeeper/tasks/main.yml | 128 ++-- .../zookeeper/templates/zookeeper.service.j2 | 2 +- .../common/ansible/playbooks/zookeeper.yml | 4 + .../configuration/feature-mapping.yml | 13 +- .../configuration/haproxy-exporter.yml | 13 +- .../common/defaults/configuration/haproxy.yml | 13 +- .../defaults/configuration/image-registry.yml | 9 + .../defaults/configuration/jmx-exporter.yml | 5 +- .../defaults/configuration/kafka-exporter.yml | 16 +- .../common/defaults/configuration/kafka.yml | 7 +- .../configuration/kubernetes-master.yml | 40 +- .../configuration/kubernetes-node.yml | 7 +- .../defaults/configuration/node-exporter.yml | 10 +- .../defaults/configuration/postgresql.yml | 1 + .../defaults/configuration/prometheus.yml | 21 +- .../defaults/configuration/repository.yml | 7 + .../defaults/configuration/shared-config.yml | 14 + .../defaults/configuration/zookeeper.yml | 2 +- .../configuration/image-registry.yml | 1 + .../validation/configuration/repository.yml | 1 + .../configuration/shared-config.yml | 1 + 140 files changed, 3643 insertions(+), 1055 deletions(-) create mode 100644 core/src/epicli/cli/engine/PrepareEngine.py create mode 100644 core/src/epicli/data/common/ansible/playbooks/download.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/group_vars/all.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/image_registry.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/repository.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/repository_setup.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/repository_teardown.yml delete mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/Debian.yml delete mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_file.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_image.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/main.yml delete mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/grafana/templates/grafana_rh.repo.j2 delete mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/debian.yml delete mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/redhat.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/image_registry/meta/main.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/image_registry/tasks/main.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/load-image.yml rename core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/{files/calico.yml => templates/calico.yml.j2} (98%) rename core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/{files/coredns-config.yml => templates/coredns-config.yml.j2} (98%) rename core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/{files/kube-flannel.yml => templates/kube-flannel.yml.j2} (93%) rename core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/{files/kubernetes-dashboard.yml => templates/kubernetes-dashboard.yml.j2} (97%) create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/add-epirepo-client.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/create-enabled-system-repos-list.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-epirepo-client.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-system-repos.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/enable-system-repos.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/add-epirepo-client.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/create-enabled-system-repos-list.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-epirepo-client.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-system-repos.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/enable-system-repos.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/requirements.txt create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/requirements.txt create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/add-repositories.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/common.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/download-requirements.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/requirements.txt create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/create-repository.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/disable-repository-server.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/dpkg-scanpackages create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/RedHat/create-repository.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/RedHat/disable-repository-server.sh create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/Debian/setup.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/Debian/teardown.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/RedHat/setup.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/RedHat/teardown.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/download-requirements.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/setup.yml create mode 100644 core/src/epicli/data/common/ansible/playbooks/roles/repository/tasks/teardown.yml create mode 100644 core/src/epicli/data/common/defaults/configuration/image-registry.yml create mode 100644 core/src/epicli/data/common/defaults/configuration/repository.yml create mode 100644 core/src/epicli/data/common/defaults/configuration/shared-config.yml create mode 100644 core/src/epicli/data/common/validation/configuration/image-registry.yml create mode 100644 core/src/epicli/data/common/validation/configuration/repository.yml create mode 100644 core/src/epicli/data/common/validation/configuration/shared-config.yml diff --git a/core/src/epicli/.gitignore b/core/src/epicli/.gitignore index ec7a9fe64d..7a68a2f912 100644 --- a/core/src/epicli/.gitignore +++ b/core/src/epicli/.gitignore @@ -28,7 +28,7 @@ share/python-wheels/ *.egg MANIFEST -requirements.txt +/requirements.txt # PyInstaller # Usually these files are written by a python script from a template diff --git a/core/src/epicli/cli/engine/BuildEngine.py b/core/src/epicli/cli/engine/BuildEngine.py index 81f9533e03..33f5992217 100644 --- a/core/src/epicli/cli/engine/BuildEngine.py +++ b/core/src/epicli/cli/engine/BuildEngine.py @@ -74,7 +74,7 @@ def process_configuration_docs(self): def collect_infrastructure_config(self): with provider_class_loader(self.cluster_model.provider, 'InfrastructureConfigCollector')( - [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs]) as config_collector: + [*self.configuration_docs, *self.infrastructure_docs]) as config_collector: config_collector.run() def validate(self): @@ -107,7 +107,7 @@ def apply(self): self.collect_infrastructure_config() # Merge all the docs - docs = [*self.input_docs, *self.configuration_docs, *self.infrastructure_docs] + docs = [*self.configuration_docs, *self.infrastructure_docs] # Save docs to manifest file save_manifest(docs, self.cluster_model.specification.name) diff --git a/core/src/epicli/cli/engine/PrepareEngine.py b/core/src/epicli/cli/engine/PrepareEngine.py new file mode 100644 index 0000000000..a9c55f173a --- /dev/null +++ b/core/src/epicli/cli/engine/PrepareEngine.py @@ -0,0 +1,53 @@ +import os +import stat +import inspect +import shutil +from os.path import dirname + +from cli.helpers.Step import Step +from cli.helpers.data_loader import DATA_FOLDER_PATH +from cli.helpers.Config import Config +from cli.helpers.build_saver import copy_files_recursively + + +class PrepareEngine(Step): + PREPARE_PATH = DATA_FOLDER_PATH + '/common/ansible/playbooks/roles/repository/files/download-requirements' + + def __init__(self, input_data): + super().__init__(__name__) + self.os = input_data.os + + def __enter__(self): + super().__enter__() + return self + + def __exit__(self, exc_type, exc_value, traceback): + super().__exit__(exc_type, exc_value, traceback) + + def prepare(self): + prepare_src = os.path.join(self.PREPARE_PATH, self.os) + skopeo_src = os.path.join(dirname(dirname(inspect.getfile(os))), 'skopeo_linux') + prepare_dst = os.path.join(Config().output_dir, 'prepare_scripts') + + if not os.path.exists(prepare_src): + supported_os = os.listdir(self.PREPARE_PATH) + raise Exception(f'Unsupported OS: {self.os}. Currently supported: {supported_os}') + + if not os.path.exists(skopeo_src): + raise Exception('Skopeo dependency not found') + + # copy files to output dir + copy_files_recursively(prepare_src, prepare_dst) + shutil.copy(skopeo_src, prepare_dst) + + # make sure the scripts and skopeo are executable + self.make_file_executable(os.path.join(prepare_dst, 'skopeo_linux')) + self.make_file_executable(os.path.join(prepare_dst, 'download-requirements.sh')) + + self.logger.info(f'Prepared files for downloading the offline requirements in: {prepare_dst}') + return 0 + + @staticmethod + def make_file_executable(file): + executable_stat = os.stat(file) + os.chmod(file, executable_stat.st_mode | stat.S_IEXEC) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py index 668dfca621..d282577538 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleRunner.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleRunner.py @@ -1,5 +1,8 @@ +import inspect import os import time +import shutil +from os.path import dirname from cli.engine.ansible.AnsibleCommand import AnsibleCommand from cli.engine.ansible.AnsibleInventoryCreator import AnsibleInventoryCreator @@ -8,10 +11,11 @@ from cli.helpers.build_saver import get_inventory_path, get_ansible_path, copy_files_recursively from cli.helpers.naming_helpers import to_role_name from cli.helpers.data_loader import DATA_FOLDER_PATH +from cli.helpers.Config import Config class AnsibleRunner(Step): - ANSIBLE_PLAYBOOKS_PATH = DATA_FOLDER_PATH + "/common/ansible/playbooks/" + ANSIBLE_PLAYBOOKS_PATH = DATA_FOLDER_PATH + '/common/ansible/playbooks/' def __init__(self, cluster_model, config_docs): super().__init__(__name__) @@ -42,21 +46,25 @@ def run(self): copy_files_recursively(AnsibleRunner.ANSIBLE_PLAYBOOKS_PATH, get_ansible_path(self.cluster_model.specification.name)) - # todo: install packages to run ansible on Red Hat hosts - self.ansible_command.run_task_with_retries(hosts="all", inventory=inventory_path, module="raw", - args="cat /etc/lsb-release | grep -i DISTRIB_ID | grep -i ubuntu && " - "sudo apt-get update && sudo apt-get install -y python-simplejson " - "|| echo 'Cannot find information about Ubuntu distribution'", retries=5) + # copy skopeo so Ansible can move it to the repositry machine + if not Config().offline_requirements: + shutil.copy(os.path.join(dirname(dirname(inspect.getfile(os))), 'skopeo_linux'), '/tmp') self.ansible_vars_generator.run() - + self.logger.info('Setting up repository for cluster provisioning. This will take a while...') self.ansible_command.run_playbook_with_retries(inventory=inventory_path, - playbook_path=self.playbook_path('common'), + playbook_path=self.playbook_path('repository_setup'), retries=5) + self.ansible_command.run_playbook(inventory=inventory_path, + playbook_path=self.playbook_path('common')) + enabled_roles = self.inventory_creator.get_enabled_roles() for role in enabled_roles: self.ansible_command.run_playbook(inventory=inventory_path, playbook_path=self.playbook_path(to_role_name(role))) + + self.ansible_command.run_playbook(inventory=inventory_path, + playbook_path=self.playbook_path('repository_teardown')) diff --git a/core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py b/core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py index e1724d7894..273e20b2a0 100644 --- a/core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py +++ b/core/src/epicli/cli/engine/ansible/AnsibleVarsGenerator.py @@ -51,6 +51,8 @@ def populate_group_vars(self, ansible_dir): main_vars = ObjDict() main_vars = self.add_admin_user_name(main_vars) main_vars = self.add_validate_certs(main_vars) + main_vars = self.add_shared_config(main_vars) + main_vars = self.add_offline_requirements(main_vars) vars_dir = os.path.join(ansible_dir, 'group_vars') if not os.path.exists(vars_dir): @@ -59,22 +61,24 @@ def populate_group_vars(self, ansible_dir): vars_file_name = 'all.yml' vars_file_path = os.path.join(vars_dir, vars_file_name) - with open(vars_file_path, 'w') as stream: + with open(vars_file_path, 'a') as stream: dump(main_vars, stream) def add_admin_user_name(self, document): - if document is None: - raise Exception('Config is empty for: ' + 'group_vars/all.yml') - document['admin_user'] = self.cluster_model.specification.admin_user return document def add_validate_certs(self, document): - if document is None: - raise Exception('Config is empty for: ' + 'group_vars/all.yml') - document['validate_certs'] = Config().validate_certs + return document + + def add_offline_requirements(self, document): + document['offline_requirements'] = Config().offline_requirements + return document + def add_shared_config(self, document): + shared_config_doc = select_first(self.config_docs, lambda x: x.kind == 'configuration/shared-config') + document.update(shared_config_doc.specification) return document def add_provider_info(self, document): diff --git a/core/src/epicli/cli/engine/schema/ConfigurationAppender.py b/core/src/epicli/cli/engine/schema/ConfigurationAppender.py index 4170b5c891..3e65371c8a 100644 --- a/core/src/epicli/cli/engine/schema/ConfigurationAppender.py +++ b/core/src/epicli/cli/engine/schema/ConfigurationAppender.py @@ -6,6 +6,8 @@ class ConfigurationAppender(Step): + REQUIRED_DOCS = ['configuration/feature-mapping', 'configuration/shared-config', 'epiphany-cluster'] + def __init__(self, input_docs): super().__init__(__name__) self.cluster_model = select_single(input_docs, lambda x: x.kind == 'epiphany-cluster') @@ -14,22 +16,25 @@ def __init__(self, input_docs): def run(self): configuration_docs = [] + for document_kind in ConfigurationAppender.REQUIRED_DOCS: + doc = select_first(self.input_docs, lambda x: x.kind == document_kind) + if doc is None: + doc = load_yaml_obj(types.DEFAULT, 'common', document_kind) + self.logger.info("Adding: " + doc.kind) + configuration_docs.append(doc) + else: + configuration_docs.append(doc) + for component_key, component_value in self.cluster_model.specification.components.items(): if component_value.count < 1: continue - features_map = select_first(self.input_docs, lambda x: x.kind == 'configuration/feature-mapping') - if features_map is None: - features_map = select_first(configuration_docs, lambda x: x.kind == 'configuration/feature-mapping') - - if features_map is None: - features_map = load_yaml_obj(types.DEFAULT, 'common', 'configuration/feature-mapping') - self.logger.info("Adding: " + features_map.kind) - configuration_docs.append(features_map) - + features_map = select_first(configuration_docs, lambda x: x.kind == 'configuration/feature-mapping') config_selector = component_value.configuration for feature_key in features_map.specification.roles_mapping[component_key]: config = select_first(self.input_docs, lambda x: x.kind == 'configuration/' + feature_key and x.name == config_selector) + if config is not None: + configuration_docs.append(config) if config is None: config = select_first(configuration_docs, lambda x: x.kind == 'configuration/' + feature_key and x.name == config_selector) diff --git a/core/src/epicli/cli/epicli.py b/core/src/epicli/cli/epicli.py index 2b6158c457..53108897cb 100644 --- a/core/src/epicli/cli/epicli.py +++ b/core/src/epicli/cli/epicli.py @@ -8,6 +8,7 @@ from cli.engine.PatchEngine import PatchEngine from cli.engine.DeleteEngine import DeleteEngine from cli.engine.InitEngine import InitEngine +from cli.engine.PrepareEngine import PrepareEngine from cli.helpers.Log import Log from cli.helpers.Config import Config from cli.version import VERSION @@ -60,6 +61,7 @@ def main(): backup_parser(subparsers) recovery_parser(subparsers) delete_parser(subparsers) + prepare_parser(subparsers) # check if there were any variables and display full help if len(sys.argv) < 2: @@ -78,6 +80,8 @@ def main(): config.log_type = args.log_type config.log_count = args.log_count config.validate_certs = True if args.validate_certs == 'true' else False + if 'offline_requirements' in args and not args.offline_requirements is None: + config.offline_requirements = args.offline_requirements config.debug = args.debug config.auto_approve = args.auto_approve @@ -114,6 +118,8 @@ def apply_parser(subparsers): help='File with infrastructure/configuration definitions to use.') sub_parser.add_argument('--no-infra', dest='no_infra', action="store_true", help='Skip infrastructure provisioning.') + sub_parser.add_argument('--offline-requirements', dest='offline_requirements', type=str, + help='Path to the folder with pre-prepared offline requirements.') def run_apply(args): adjust_paths_from_file(args) @@ -198,11 +204,30 @@ def run_recovery(args): sub_parser.set_defaults(func=run_recovery) +def prepare_parser(subparsers): + sub_parser = subparsers.add_parser('prepare', description='Creates a folder with all prerequisites to setup the offline requirements to install a cluster offline.') + sub_parser.add_argument('--os', type=str, required=True, dest='os', + help='The OS to prepare the offline requirements for.') + + def run_prepare(args): + adjust_paths_from_output_dir() + with PrepareEngine(args) as engine: + return engine.prepare() + + sub_parser.set_defaults(func=run_prepare) + + def experimental_query(): if not query_yes_no('This is an experimental feature and could change at any time. Do you want to continue?'): sys.exit(0) +def adjust_paths_from_output_dir(): + if not Config().output_dir: + Config().output_dir = os.getcwd() # Default to working dir so we can at least write logs. + dump_config(Config()) + + def adjust_paths_from_file(args): if not os.path.isabs(args.file): args.file = os.path.join(os.getcwd(), args.file) diff --git a/core/src/epicli/cli/helpers/Config.py b/core/src/epicli/cli/helpers/Config.py index 5bd6583e35..ddce0b0912 100644 --- a/core/src/epicli/cli/helpers/Config.py +++ b/core/src/epicli/cli/helpers/Config.py @@ -1,5 +1,6 @@ import os + class Config: class __ConfigBase: def __init__(self): @@ -18,6 +19,7 @@ def __init__(self): self._validate_certs = True self._debug = False self._auto_approve = False + self._offline_requirements = '' @property def docker_cli(self): @@ -93,8 +95,8 @@ def debug(self): @debug.setter def debug(self, debug): if not debug is None: - self._debug = debug - + self._debug = debug + @property def auto_approve(self): return self._auto_approve @@ -102,8 +104,20 @@ def auto_approve(self): @auto_approve.setter def auto_approve(self, auto_approve): if not auto_approve is None: - self._auto_approve = auto_approve - + self._auto_approve = auto_approve + + @property + def offline_requirements(self): + return self._offline_requirements + + @offline_requirements.setter + def offline_requirements(self, offline_requirements): + if not offline_requirements is None: + # To make sure Ansible copies the content of the folder the the repository host. + if not offline_requirements.endswith('/'): + offline_requirements = f'{offline_requirements}/' + self._offline_requirements = offline_requirements + instance = None def __new__(cls): diff --git a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml index ea28c68cbb..66b490d0cf 100644 --- a/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/aws/defaults/infrastructure/virtual-machine.yml @@ -51,6 +51,26 @@ specification: destination_port_range: "9100" source_address_prefix: "10.1.0.0/20" destination_address_prefix: "0.0.0.0/0" + - name: image_registry + description: Allow image registry traffic + priority: 303 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "80" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: package_repository + description: Allow package repository traffic + priority: 304 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "5000" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: out description: Allow out priority: 101 @@ -167,7 +187,7 @@ specification: source_port_range: "*" destination_port_range: "0" source_address_prefix: "0.0.0.0/0" - destination_address_prefix: "0.0.0.0/0" + destination_address_prefix: "0.0.0.0/0" --- kind: infrastructure/virtual-machine version: 0.4.0 @@ -243,6 +263,16 @@ specification: destination_port_range: "22" source_address_prefix: "0.0.0.0/0" destination_address_prefix: "0.0.0.0/0" + - name: repository + description: Allow repository traffic + priority: 302 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "80" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" - name: node_exporter description: Allow node_exporter traffic priority: 302 diff --git a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml index 8aec07e5a7..dca2fce330 100644 --- a/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml +++ b/core/src/epicli/data/azure/defaults/infrastructure/virtual-machine.yml @@ -139,6 +139,26 @@ specification: destination_port_range: "0" source_address_prefix: "10.1.2.0/24" destination_address_prefix: "0.0.0.0/0" + - name: package_repository + description: Allow package repository traffic + priority: 205 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "80" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" + - name: image_repository + description: Allow image repository traffic + priority: 206 + direction: Inbound + access: Allow + protocol: Tcp + source_port_range: "*" + destination_port_range: "5000" + source_address_prefix: "10.1.0.0/20" + destination_address_prefix: "0.0.0.0/0" # - name: node2-subnet-traffic # description: Allow node subnet traffic # priority: 102 diff --git a/core/src/epicli/data/common/ansible/playbooks/download.yml b/core/src/epicli/data/common/ansible/playbooks/download.yml new file mode 100644 index 0000000000..3169d7ee0b --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/download.yml @@ -0,0 +1,8 @@ +--- +# Ansible playbook that downloads files and images + +- hosts: 127.0.0.1 + gather_facts: no + connection: local + roles: + - download \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/elasticsearch.yml b/core/src/epicli/data/common/ansible/playbooks/elasticsearch.yml index ec9e960685..457fd925c7 100644 --- a/core/src/epicli/data/common/ansible/playbooks/elasticsearch.yml +++ b/core/src/epicli/data/common/ansible/playbooks/elasticsearch.yml @@ -1,5 +1,8 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed +- hosts: all + gather_facts: yes + tasks: [ ] - hosts: elasticsearch become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/elasticsearch_curator.yml b/core/src/epicli/data/common/ansible/playbooks/elasticsearch_curator.yml index ff232a1f5e..b85a7ef1b7 100644 --- a/core/src/epicli/data/common/ansible/playbooks/elasticsearch_curator.yml +++ b/core/src/epicli/data/common/ansible/playbooks/elasticsearch_curator.yml @@ -1,5 +1,8 @@ --- # Ansible playbook that makes sure elasticsearch-curator will be installed +- hosts: all + gather_facts: yes + tasks: [ ] - hosts: elasticsearch_curator become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/filebeat.yml b/core/src/epicli/data/common/ansible/playbooks/filebeat.yml index 7802d22f51..13fccec98e 100644 --- a/core/src/epicli/data/common/ansible/playbooks/filebeat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/filebeat.yml @@ -1,6 +1,10 @@ --- # Ansible playbook that installs and configures Filebeat +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: elasticsearch:kibana # To gather facts tasks: [ ] diff --git a/core/src/epicli/data/common/ansible/playbooks/grafana.yml b/core/src/epicli/data/common/ansible/playbooks/grafana.yml index 907cb69f8b..77eca32da8 100644 --- a/core/src/epicli/data/common/ansible/playbooks/grafana.yml +++ b/core/src/epicli/data/common/ansible/playbooks/grafana.yml @@ -1,4 +1,7 @@ --- +- hosts: all + gather_facts: yes + tasks: [ ] - hosts: grafana become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/group_vars/all.yml b/core/src/epicli/data/common/ansible/playbooks/group_vars/all.yml new file mode 100644 index 0000000000..a0f0814b97 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/group_vars/all.yml @@ -0,0 +1,5 @@ +local_repository_url: "http://{{ hostvars[groups['repository'][0]]['ansible_default_ipv4']['address'] }}/epirepo" +repository_url: "{{ custom_repository_url | default(local_repository_url, true) }}" + +local_image_registry: "{{ groups['image_registry'] | first }}:5000" +image_registry_address: "{{ local_image_registry }}" # TODO support custom_image_registry_address with user defined repo diff --git a/core/src/epicli/data/common/ansible/playbooks/haproxy.yml b/core/src/epicli/data/common/ansible/playbooks/haproxy.yml index 83e00bb182..b1233c983b 100644 --- a/core/src/epicli/data/common/ansible/playbooks/haproxy.yml +++ b/core/src/epicli/data/common/ansible/playbooks/haproxy.yml @@ -1,8 +1,8 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed - - hosts: all - tasks: [ ] + gather_facts: yes + tasks: [ ] - hosts: haproxy become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/haproxy_exporter.yml b/core/src/epicli/data/common/ansible/playbooks/haproxy_exporter.yml index c2a6367627..1177e49694 100644 --- a/core/src/epicli/data/common/ansible/playbooks/haproxy_exporter.yml +++ b/core/src/epicli/data/common/ansible/playbooks/haproxy_exporter.yml @@ -1,8 +1,8 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed - - hosts: all - tasks: [ ] + gather_facts: yes + tasks: [ ] - hosts: haproxy_exporter become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/image_registry.yml b/core/src/epicli/data/common/ansible/playbooks/image_registry.yml new file mode 100644 index 0000000000..fee200322e --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/image_registry.yml @@ -0,0 +1,12 @@ +--- +# Ansible playbook that makes sure the base items for all nodes are installed + +- hosts: all + gather_facts: yes + tasks: [ ] + +- hosts: image_registry + become: true + become_method: sudo + roles: + - image_registry diff --git a/core/src/epicli/data/common/ansible/playbooks/jmx_exporter.yml b/core/src/epicli/data/common/ansible/playbooks/jmx_exporter.yml index 0ea6105973..cb29ee08b9 100644 --- a/core/src/epicli/data/common/ansible/playbooks/jmx_exporter.yml +++ b/core/src/epicli/data/common/ansible/playbooks/jmx_exporter.yml @@ -1,5 +1,9 @@ --- +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: jmx_exporter become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/kafka.yml b/core/src/epicli/data/common/ansible/playbooks/kafka.yml index 5e594c88a3..3b7aa6da2d 100644 --- a/core/src/epicli/data/common/ansible/playbooks/kafka.yml +++ b/core/src/epicli/data/common/ansible/playbooks/kafka.yml @@ -1,6 +1,10 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: kafka become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/kafka_exporter.yml b/core/src/epicli/data/common/ansible/playbooks/kafka_exporter.yml index ded5987967..b727f6fbc7 100644 --- a/core/src/epicli/data/common/ansible/playbooks/kafka_exporter.yml +++ b/core/src/epicli/data/common/ansible/playbooks/kafka_exporter.yml @@ -1,5 +1,9 @@ --- +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: kafka_exporter become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/kibana.yml b/core/src/epicli/data/common/ansible/playbooks/kibana.yml index 0cacde8764..882d4c66ff 100644 --- a/core/src/epicli/data/common/ansible/playbooks/kibana.yml +++ b/core/src/epicli/data/common/ansible/playbooks/kibana.yml @@ -1,6 +1,10 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: kibana become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/kubernetes_master.yml b/core/src/epicli/data/common/ansible/playbooks/kubernetes_master.yml index 4ad62c4747..271bff96f2 100644 --- a/core/src/epicli/data/common/ansible/playbooks/kubernetes_master.yml +++ b/core/src/epicli/data/common/ansible/playbooks/kubernetes_master.yml @@ -1,6 +1,10 @@ --- # Ansible playbook that makes sure the base items for all nodes are installed +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: kubernetes_master become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/node_exporter.yml b/core/src/epicli/data/common/ansible/playbooks/node_exporter.yml index 8a3c897dfb..2d8d9b97e0 100644 --- a/core/src/epicli/data/common/ansible/playbooks/node_exporter.yml +++ b/core/src/epicli/data/common/ansible/playbooks/node_exporter.yml @@ -1,4 +1,7 @@ --- +- hosts: all + gather_facts: yes + tasks: [ ] - hosts: node_exporter become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/postgresql.yml b/core/src/epicli/data/common/ansible/playbooks/postgresql.yml index 0a9e26422b..2b4496aba5 100644 --- a/core/src/epicli/data/common/ansible/playbooks/postgresql.yml +++ b/core/src/epicli/data/common/ansible/playbooks/postgresql.yml @@ -1,5 +1,8 @@ --- # Ansible playbook that installs and performs basic configuration of postgresql +- hosts: all + gather_facts: yes + tasks: [ ] - hosts: postgresql become: true diff --git a/core/src/epicli/data/common/ansible/playbooks/prometheus.yml b/core/src/epicli/data/common/ansible/playbooks/prometheus.yml index 780bfa3566..d45bc35088 100644 --- a/core/src/epicli/data/common/ansible/playbooks/prometheus.yml +++ b/core/src/epicli/data/common/ansible/playbooks/prometheus.yml @@ -1,5 +1,9 @@ --- +- hosts: all + gather_facts: yes + tasks: [ ] + - hosts: prometheus become: true become_method: sudo diff --git a/core/src/epicli/data/common/ansible/playbooks/repository.yml b/core/src/epicli/data/common/ansible/playbooks/repository.yml new file mode 100644 index 0000000000..3fcc144ef1 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/repository.yml @@ -0,0 +1,5 @@ +--- +# This playbook is empty by purpose, just to enable repository role in configuration/feature-mapping +# to populate defaults/configuration to Ansible vars +- hosts: [] + tasks: [] \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/repository_setup.yml b/core/src/epicli/data/common/ansible/playbooks/repository_setup.yml new file mode 100644 index 0000000000..21b2875478 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/repository_setup.yml @@ -0,0 +1,10 @@ +--- +# Ansible playbook for disabling/enabling repositories before/after Epiphany installation + +- hosts: all + become: true + become_method: sudo + tasks: + - import_role: + name: repository + tasks_from: setup diff --git a/core/src/epicli/data/common/ansible/playbooks/repository_teardown.yml b/core/src/epicli/data/common/ansible/playbooks/repository_teardown.yml new file mode 100644 index 0000000000..d2a01fd20e --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/repository_teardown.yml @@ -0,0 +1,10 @@ +--- +# Ansible playbook for disabling/enabling repositories before/after Epiphany installation + +- hosts: all + become: true + become_method: sudo + tasks: + - import_role: + name: repository + tasks_from: teardown diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/Debian.yml index 50110206ac..c5c051e838 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/Debian.yml @@ -1,8 +1,6 @@ --- # Common Debian family of specific tasks - - - name: Install selinux packages as prerequisite for SELinux module apt: name: @@ -11,9 +9,6 @@ update_cache: yes state: present - - - - name: Install debian family packages apt: name: @@ -39,6 +34,7 @@ - ethtool - telnet - ufw + - jq update_cache: yes state: present diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/RedHat.yml index 8cd21dde80..c61939f989 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/RedHat.yml @@ -1,18 +1,12 @@ --- # Common Redhat family of specific tasks -# Install RedHat extras if on redhat family. This needs to be done first -- name: Install Extras packages - yum: - name: https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - state: latest - # Subscriptions with certs: subscription-manager repos --enable "rhel-*-optional-rpms" --enable "rhel-*-extras-rpms" # w/o subscription https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - name: Install RedHat family packages yum: - name: + name: - libselinux-python - libsemanage-python - firewalld @@ -30,12 +24,14 @@ - sysstat - python-setuptools - openssl + - yum-utils - yum-versionlock - logrotate - ebtables - ethtool - telnet - update_cache: yes + - jq + update_cache: yes state: present register: result retries: 3 diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/main.yml index bc783c3365..a7cdcd7061 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/common/tasks/main.yml @@ -20,30 +20,6 @@ - name: Print environment variables debug: msg={{ env_output.stdout_lines }} -# TODO: Checking sha512 of jq -- name: Gather prereqs - get_url: - url: https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 - dest: /usr/local/bin/jq - mode: 0755 - validate_certs: "{{ validate_certs | bool}}" - -- name: Get sha512 sum of archive - stat: - path: "/usr/local/bin/jq" - checksum_algorithm: sha512 - get_checksum: yes - register: jq_download_stat - -- name: Display sha of archive - debug: - msg: "Jq SHA512: {{ jq_download_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: jq_download_stat.stat.checksum != "aaa016d57ab8351360d02186809ade9cdecd3eb20df7a8cf05cd5d1037c4d36efae9e1bb0102d175c91b530b0309f24b48d579544249da7cbd50f721332617b9" - - name: Adjust swappiness parameter sysctl: name: vm.swappiness @@ -109,8 +85,6 @@ changed_when: false when: ansible_selinux is defined and ansible_selinux != False and ansible_selinux.status == 'enabled' - - - name: Motd cross-bones copy: src: motd.tail @@ -134,17 +108,6 @@ owner: root group: root -- name: PIP via easy_install - easy_install: - name: pip - state: latest - when: not ansible_distribution_version == "18.04" - -- name: PIP install - Ubuntu 18.04 - apt: name=python-pip update_cache=yes state=present - when: ansible_os_family == "Debian" and ansible_distribution_version == "18.04" - - - include_tasks: epiuser.yml tags: - epiuser diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/defaults/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/docker/defaults/main.yml index 0a4bc44e9f..3ba1cf5165 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/defaults/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/docker/defaults/main.yml @@ -3,3 +3,5 @@ docker_logging: log_opts: max_file_size: 10m # The maximum size of the log before it is rolled. A positive integer plus a modifier representing the unit of measure (k, m, or g) max_files: 2 # The maximum number of log files that can be present + +docker_version: 18.09.6 \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/Debian.yml deleted file mode 100644 index b6568fe19e..0000000000 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/Debian.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Ensure dependencies are installed - apt: - name: - - apt-transport-https - - ca-certificates - state: present - -- name: Add Docker apt key - apt_key: - url: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" - id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 - state: present - register: add_repository_key - -- name: Add Docker-CE stable repo - apt_repository: - repo: "deb [arch=amd64] https://download.docker.com/linux/{{ ansible_distribution|lower }} {{ ansible_distribution_release }} stable" - state: present - update_cache: true - -- name: Install Docker - apt: - name: "docker-ce=5:18.09.6~3-0~{{ ansible_distribution|lower }}-{{ ansible_distribution_release }}" - state: present - update_cache: true \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml deleted file mode 100644 index 4560ac582f..0000000000 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/RedHat.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -- name: Add Docker-CE stable repo - yum_repository: - name: docker-ce-stable - description: Docker CE Stable Repo - baseurl: https://download.docker.com/linux/centos/7/$basearch/stable - gpgkey: https://download.docker.com/linux/centos/gpg - gpgcheck: yes - -- name: Install container-selinux for RHEL 7.6 and later - yum: - name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.107-1.el7_6.noarch.rpm - state: present - update_cache: yes - when: ansible_distribution_version is version('7.6', '>=') - -- name: Install container-selinux for 7.5 and older - yum: - name: http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.107-3.el7.noarch.rpm - state: present - update_cache: yes - when: ansible_distribution_version is version('7.5', '<=') - -- name: Install Docker - yum: - name: docker-ce-18.09.6-3.el7 - state: present - update_cache: yes diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/main.yml index 78108d6a5d..eaea6119e9 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/docker/tasks/main.yml @@ -1,6 +1,25 @@ --- # Docker (used by master & worker as dependency) -- include_tasks: "{{ ansible_os_family }}.yml" +- name: Install Docker for Debian family + package: + name: "{{ item }}" + state: present + loop: + - apt-transport-https + - ca-certificates + - containerd.io + - docker-ce-cli=5:18.09.* + - docker-ce=5:18.09.* + when: ansible_os_family == "Debian" + +- name: Install Docker for RedHat family + package: + name: "{{ item }}" + state: present + loop: + - docker-ce-cli-18.09.* + - docker-ce-18.09.* + when: ansible_os_family == "RedHat" - include_tasks: configure-docker.yml diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/docker/templates/daemon.json.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/docker/templates/daemon.json.j2 index 213544beab..4ec3d3d69c 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/docker/templates/daemon.json.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/docker/templates/daemon.json.j2 @@ -1,4 +1,9 @@ { + {% if custom_image_registry_address|length == 0 %} + "insecure-registries" : ["{{ image_registry_address }}"], + {% endif %} + + "log-driver": "json-file", "log-opts": { "max-size": "{{ docker_logging.log_opts.max_file_size }}", diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_file.yml b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_file.yml new file mode 100644 index 0000000000..f943e4753c --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_file.yml @@ -0,0 +1,12 @@ +--- + +- name: "Download file {{ file_name }}" + get_url: + url: "{{ repository_url }}/files/{{ file_name }}" + dest: "{{ download_directory }}" + validate_certs: "{{ validate_certs }}" + register: get_url_result + until: "'OK' in get_url_result.msg or 'file already exists' in get_url_result.msg" + retries: "3" + delay: "2" + become: false diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_image.yml b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_image.yml new file mode 100644 index 0000000000..d8e12f15ee --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/download_image.yml @@ -0,0 +1,12 @@ +--- + +- name: Download image {{ file_name }} + get_url: + url: "{{ repository_url }}/images/{{ file_name }}" + dest: "{{ download_directory }}" + validate_certs: "{{ validate_certs }}" + register: get_url_result + until: "'OK' in get_url_result.msg or 'file already exists' in get_url_result.msg" + retries: "3" + delay: "2" + become: false \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/main.yml new file mode 100644 index 0000000000..8696dc18c9 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/download/tasks/main.yml @@ -0,0 +1,3 @@ +--- + +# This role is only included in other roles to download from repository \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/Debian.yml index 5f9d5e555b..f4676ada49 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/Debian.yml @@ -1,32 +1,14 @@ ---- -## Elasticsearch master +# splitted to separate tasks to make it work on Debian/Ubuntu: +# https://github.com/elastic/elasticsearch/issues/33607#issue-359124678 -- name: Install debian family packages - apt: +- name: Install prerequisites for Elasticsearch + apt: name: - - openjdk-8-jre - update_cache: yes + - openjdk-8-jre-headless state: present -- name: Install Elasticsearch Package - apt: - deb: "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-{{ specification.elasticsearch_version }}.deb" - when: - - groups['elasticsearch'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/elasticsearch/elasticsearch.yml - regexp: '^#network.host: 192.168.0.1$' - replace: "network.host: {{ hostvars[groups['elasticsearch'][0]]['ansible_default_ipv4']['address'] }}" - backup: no - when: - - groups['elasticsearch'][0] == inventory_hostname - -- name: Start services - service: - name: elasticsearch - state: started - enabled: yes - when: - - groups['elasticsearch'][0] == inventory_hostname +- name: Install Elasticsearch package + apt: + name: + - elasticsearch-oss + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/RedHat.yml index ff92dfc27f..223175ae53 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/RedHat.yml @@ -1,36 +1,7 @@ ---- -## Elasticsearch master - -- name: Install RedHat family packages +- name: Install Elasticsearch package yum: name: - - java-1.8.0-openjdk + - java-1.8.0-openjdk-headless + - elasticsearch-oss update_cache: yes - state: present - register: result - retries: 3 - delay: 1 - until: result is succeeded - -- name: Install Elasticsearch Package - yum: - name: "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-{{ specification.elasticsearch_version }}.rpm" - when: - - groups['elasticsearch'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/elasticsearch/elasticsearch.yml - regexp: '^#network.host: 192.168.0.1$' - replace: "network.host: {{ hostvars[groups['elasticsearch'][0]]['ansible_default_ipv4']['address'] }}" - backup: no - when: - - groups['elasticsearch'][0] == inventory_hostname - -- name: Start services - service: - name: elasticsearch - state: started - enabled: yes - when: - - groups['elasticsearch'][0] == inventory_hostname + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/main.yml index 4f0f1c848d..1119f13cab 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch/tasks/main.yml @@ -1,5 +1,22 @@ --- -## Elasticsearch master - include_tasks: "set-pam-limits.yml" -- include_tasks: "{{ ansible_os_family }}.yml" + +- include_tasks: "{{ ansible_os_family }}.yml" + +- name: Replace with interface + replace: + path: /etc/elasticsearch/elasticsearch.yml + regexp: '^#network.host: 192.168.0.1$' + replace: "network.host: {{ hostvars[groups['elasticsearch'][0]]['ansible_default_ipv4']['address'] }}" + backup: no + when: + - groups['elasticsearch'][0] == inventory_hostname + +- name: Start services + service: + name: elasticsearch + state: started + enabled: yes + when: + - groups['elasticsearch'][0] == inventory_hostname diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/Debian.yml index 5b107565eb..be4d6609c5 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/Debian.yml @@ -1,7 +1,6 @@ ---- - -- name: Install Elasticsearch-Curator Package - apt: - deb: "https://packages.elastic.co/curator/5/debian9/pool/main/e/elasticsearch-curator/elasticsearch-curator_{{ specification.debian_curator_version }}.deb" - - +- name: Install Elasticsearch-Curator package + apt: + name: + - elasticsearch-curator + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/RedHat.yml index 047b9a2faf..f5ef0ddd31 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/RedHat.yml @@ -1,6 +1,6 @@ ---- - -- name: Install Elasticsearch-Curator Package +- name: Install Elasticsearch-Curator package yum: - name: "https://packages.elastic.co/curator/5/centos/7/Packages/elasticsearch-curator-{{ specification.redhat_curator_version }}.rpm" - + name: + - elasticsearch-curator + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/main.yml index f3c7dd6fba..23b7c5a042 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/elasticsearch_curator/tasks/main.yml @@ -1,6 +1,6 @@ --- -- include_tasks: "{{ ansible_os_family }}.yml" +- include_tasks: "{{ ansible_os_family }}.yml" - name: Configure cron jobs for Elasticsearch Curator cron: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/Debian.yml index a763b459ea..bd4602789f 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/Debian.yml @@ -1,7 +1,6 @@ ---- -## Filebeat Debian - -- name: Install Filebeat package +- name: Install Filbeat package apt: - deb: "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-oss-{{ specification.filebeat_version }}-amd64.deb" - state: present + name: + - filebeat + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/RedHat.yml index a1ea711375..2613b00908 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/RedHat.yml @@ -1,7 +1,6 @@ ---- -## Filebeat Red Hat - -- name: Install Filebeat package - yum: - name: "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-oss-{{ specification.filebeat_version }}-x86_64.rpm" +- name: Install Filbeat package + yum: + name: + - filebeat + update_cache: yes state: present diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/main.yml index d59f5c3687..fa7b8026de 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/filebeat/tasks/main.yml @@ -1,8 +1,6 @@ --- # Filebeat - -- name: Include {{ ansible_os_family }} family tasks - include_tasks: "{{ ansible_os_family }}.yml" +- include_tasks: "{{ ansible_os_family }}.yml" - name: Include configuration tasks include_tasks: configure-filebeat.yml diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/install.yml b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/install.yml index d54c71f8bf..a1f1b4ba25 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/install.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/install.yml @@ -1,12 +1,4 @@ --- -- name: Install dependencies - package: - name: "{{ grafana_dependencies }}" - state: present - register: _install_dep_packages - until: _install_dep_packages is succeeded - retries: 5 - delay: 2 - name: Remove conflicting grafana packages package: @@ -14,50 +6,27 @@ state: absent register: _old_grafana_pkgs -- name: Clean apt cache - command: apt clean - when: - - _old_grafana_pkgs is changed - - ansible_pkg_mgr == "apt" - -- name: Add Grafana repository file [RHEL/CentOS] - template: - src: "grafana_rh.repo.j2" - dest: "/etc/yum.repos.d/grafana.repo" - force: true - backup: true - when: ansible_pkg_mgr in ['yum', 'dnf'] - -- block: - - name: Import Grafana GPG signing key [Debian/Ubuntu] - apt_key: - url: "https://packages.grafana.com/gpg.key" - state: present - validate_certs: false - register: _add_apt_key - until: _add_apt_key is succeeded - retries: 5 - delay: 2 +- name: Install dependencies for Debian family + package: + name: "{{ item }}" + state: present + loop: + - apt-transport-https + - adduser + - ca-certificates + - libfontconfig + - gnupg2 + when: ansible_os_family == "Debian" - - name: Add Grafana repository [Debian/Ubuntu] - apt_repository: - repo: deb https://packages.grafana.com/oss/deb stable main - state: present - update_cache: true - register: _update_apt_cache - until: _update_apt_cache is succeeded - retries: 5 - delay: 2 - when: - - ansible_pkg_mgr == "apt" - environment: "{{ grafana_environment }}" +#TODO: this is a quick workaround, we should tackle versioning in a smarter way +- name: Install Grafana + package: + name: "grafana-{{ grafana_version }}" + state: present + when: ansible_os_family == "RedHat" - name: Install Grafana package: - name: "{{ grafana_package }}" - state: "{{ (grafana_version == 'latest') | ternary('latest', 'present') }}" - register: _install_packages - until: _install_packages is succeeded - retries: 5 - delay: 2 - notify: restart grafana \ No newline at end of file + name: "grafana={{ grafana_version }}" + state: present + when: ansible_os_family == "Debian" \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/main.yml index c7886b1559..d70bad335d 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/tasks/main.yml @@ -1,18 +1,4 @@ --- -- name: Gather variables for each operating system - include_vars: "{{ item }}" - with_first_found: - - "{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml" - - "{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version | lower }}.yml" - - "{{ ansible_os_family | lower }}-{{ ansible_distribution_major_version | lower }}.yml" - - "{{ ansible_distribution | lower }}.yml" - - "{{ ansible_os_family | lower }}.yml" - tags: - - grafana_install - - grafana_configure - - grafana_datasources - - grafana_notifications - - grafana_dashboards - include: preflight.yml tags: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/templates/grafana_rh.repo.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/templates/grafana_rh.repo.j2 deleted file mode 100644 index fe06dcc964..0000000000 --- a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/templates/grafana_rh.repo.j2 +++ /dev/null @@ -1,10 +0,0 @@ -{{ ansible_managed | comment }} -[grafana] -name=grafana -baseurl=https://packages.grafana.com/oss/rpm -#repo_gpgcheck=1 -enabled=1 -gpgcheck=1 -gpgkey=https://packages.grafana.com/gpg.key -sslverify=1 -sslcacert=/etc/pki/tls/certs/ca-bundle.crt \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/debian.yml deleted file mode 100644 index 734db9bce3..0000000000 --- a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/debian.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -grafana_package: "grafana{{ (grafana_version != 'latest') | ternary('=' ~ grafana_version, '') }}" -grafana_dependencies: - - apt-transport-https - - adduser - - ca-certificates - - libfontconfig - - gnupg2 diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/redhat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/redhat.yml deleted file mode 100644 index 0a65d61913..0000000000 --- a/core/src/epicli/data/common/ansible/playbooks/roles/grafana/vars/redhat.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -grafana_package: "grafana{{ (grafana_version != 'latest') | ternary('-' ~ grafana_version, '') }}" -grafana_dependencies: [] \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml index 8b181d86b8..d341c44c33 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy/tasks/RedHat.yml @@ -11,31 +11,6 @@ ignore_errors: true changed_when: false -- name: Check if repository file exists - stat: - path: /etc/yum.repos.d/redhat-rhui.repo - register: rhui_exist - when: - - specification.provider == "aws" - -- name: Check if Software Collections repository on EC2 exists - shell: grep -c -i rhui-REGION-rhel-server-rhscl /etc/yum.repos.d/redhat-rhui.repo - register: sc_repo_count - failed_when: "sc_repo_count.rc == 2" - when: - - specification.provider == "aws" - - rhui_exist - -- name: Enable Software Collections on EC2 - ini_file: - dest: /etc/yum.repos.d/redhat-rhui.repo - section: rhui-REGION-rhel-server-rhscl - option: enabled - value: 1 - when: - - specification.provider == "aws" - - sc_repo_count.stdout|int == 1 - - name: Install haproxy family packages yum: name: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy_exporter/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy_exporter/tasks/main.yml index 01dc71b621..28d1191f35 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/haproxy_exporter/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/haproxy_exporter/tasks/main.yml @@ -14,52 +14,16 @@ group: haproxy_exporter createhome: false -- name: Ensure download directory exists - become: false - file: - path: "{{ specification.download_directory }}/haproxy_exporter" - state: directory - delegate_to: localhost - -- name: Download haproxy_exporter binary to local folder - become: false - get_url: - url: "{{ specification.download_urls[ansible_architecture] }}" - dest: "{{ specification.download_directory }}/haproxy_exporter.tar.gz" - validate_certs: "{{ validate_certs | bool}}" - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - delegate_to: localhost - -- name: Get sha512 sum of archive - become: false - stat: - path: "{{ specification.download_directory }}/haproxy_exporter.tar.gz" - checksum_algorithm: sha512 - get_checksum: yes - register: haproxy_exporter_stat - delegate_to: localhost - -- name: Display sha of archive - debug: - msg: "Haproxy Exporter SHA512: {{ haproxy_exporter_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: haproxy_exporter_stat.stat.checksum not in specification.download_shas +- name: Set HAProxy Exporter file name to install + set_fact: + exporter_file_name: "{{ specification.file_name }}" -- name: Unpack haproxy_exporter binary - become: false - unarchive: - src: "{{ specification.download_directory }}/haproxy_exporter.tar.gz" - dest: "{{ specification.download_directory }}/haproxy_exporter" - creates: "{{ specification.download_directory }}/haproxy_exporter/haproxy_exporter" - extra_opts: [--strip-components=1] - delegate_to: localhost - check_mode: false +- name: Download HAProxy Exporter binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ exporter_file_name }}" - name: Create /opt/haproxy_exporter directories become: yes @@ -73,13 +37,18 @@ with_items: - /opt/haproxy_exporter -- name: Copy haproxy_exporter binary - copy: - src: "{{ specification.download_directory }}/haproxy_exporter/haproxy_exporter" - dest: "/opt/haproxy_exporter/haproxy_exporter" +- name: Unpack haproxy_exporter binary + become: yes + unarchive: + remote_src: yes + src: "{{ download_directory }}/{{ exporter_file_name }}" + dest: "/opt/haproxy_exporter" + creates: "/opt/haproxy_exporter/haproxy_exporter" + extra_opts: [--strip-components=1] owner: root group: haproxy_exporter - mode: 0755 + mode: 0750 + check_mode: false - name: Load stats credentials from HAProxy shell: >- diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/meta/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/meta/main.yml new file mode 100644 index 0000000000..cb7d8e0460 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: docker diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/tasks/main.yml new file mode 100644 index 0000000000..db09739cc5 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/image_registry/tasks/main.yml @@ -0,0 +1,32 @@ +--- +- name: Check if image is already loaded + shell: "docker images {{ specification.repository_image.name }} --format {{ '{{' }}.ID{{ '}}' }}" + register: image_check + ignore_errors: true + changed_when: false + +- name: Load image if does not exists + block: + - name: Download file + include_role: + name: download + tasks_from: download_image + vars: + file_name: "{{ specification.repository_image.file_name }}" + + - name: Load image {{ specification.repository_image.name }} + become: yes + shell: "docker load --input {{ download_directory }}/{{ specification.repository_image.file_name }}" + when: image_check.stdout | length == 0 + +- name: Check if registry is running + become: yes + shell: docker ps | grep registry:2 | cat + register: regitry_up_check + check_mode: no + +# todo run registry with SSL - generate/copy certs, mount it to registry container +- name: Run registry + become: yes + shell: "docker run -d -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 -p 5000:5000 --restart=always --name epiphany-registry {{ specification.repository_image.name }}" + when: regitry_up_check.stdout | length == 0 diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/jmx_exporter/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/jmx_exporter/tasks/main.yml index 08bae61d7d..c814fa5234 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/jmx_exporter/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/jmx_exporter/tasks/main.yml @@ -25,37 +25,29 @@ with_items: - "{{ specification.jmx_jars_directory }}" -# TODO: Checking sha512 -- name: Prometheus jmx | download jar - become: yes - get_url: - url: "{{ specification.download_url }}" - dest: "/opt/jmx-exporter/jmx_prometheus_javaagent-{{ specification.jmx_exporter_version }}.jar" - force: no +- name: Set JMX Exporter file name to install + set_fact: + exporter_file_name: "{{ specification.file_name }}" + +- name: Download JMX Exporter binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ exporter_file_name }}" + +- name: Copy JMX Exporter binaries + copy: + src: "{{ download_directory }}/{{ exporter_file_name }}" + dest: "/opt/jmx-exporter/{{ exporter_file_name }}" owner: "{{ specification.jmx_exporter_user }}" group: "{{ specification.jmx_exporter_group }}" - validate_certs: "{{ validate_certs | bool }}" - -- name: Get sha512 sum of archive - stat: - path: "/opt/jmx-exporter/jmx_prometheus_javaagent-{{ specification.jmx_exporter_version }}.jar" - checksum_algorithm: sha512 - get_checksum: yes - register: jmx_prometheus_download_stat - -- name: Display sha of archive - debug: - msg: "Alertmanager SHA512: {{ jmx_prometheus_download_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: jmx_prometheus_download_stat.stat.checksum != specification.download_sha + remote_src: yes - name: Prometheus jmx | symlink jar become: yes file: - src: "/opt/jmx-exporter/jmx_prometheus_javaagent-{{ specification.jmx_exporter_version }}.jar" + src: "/opt/jmx-exporter/{{ exporter_file_name }}" path: "{{ specification.jmx_path }}" force: yes state: link diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/main.yml index 88f7c15c2c..c34005f1e4 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/main.yml @@ -8,8 +8,8 @@ - include_tasks: setup-kafka.yml -- include_tasks: verify-kafka.yml - +# - include_tasks: verify-kafka.yml # todo change testing kafka to bash or remove it? (since we test it using serverspec) + - include_tasks: metrics.yml when: exporter.stat.exists diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/setup-kafka.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/setup-kafka.yml index a9afa5b422..854b252be5 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/setup-kafka.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kafka/tasks/setup-kafka.yml @@ -1,53 +1,68 @@ --- -- name: Install debian family packages - apt: - name: - - openjdk-8-jre - update_cache: yes - state: present - when: ansible_os_family == "Debian" +- name: Setup group + group: + name: "{{ specification.kafka_var.group }}" + system: yes + +- name: Setup user + user: + name: "{{ specification.kafka_var.user }}" + system: yes + group: "{{ specification.kafka_var.group }}" + shell: "/usr/sbin/nologin" -- name: Install RedHat family packages - yum: - name: - - java-1.8.0-openjdk - update_cache: yes +- name: Install Java package + package: + name: "java-1.8.0-openjdk-headless" state: present - register: result - retries: 3 - delay: 1 - until: result is succeeded when: ansible_os_family == "RedHat" -- name: Check for Kafka package - stat: - path: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" - register: kafka_check - -- name: Fetch Kafka binary package - get_url: - url: "https://archive.apache.org/dist/kafka/{{ specification.kafka_var.version }}/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" - dest: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" - validate_certs: "{{ validate_certs | bool }}" - when: not kafka_check.stat.exists - -- name: Get sha512 sum of archive - stat: - path: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" - checksum_algorithm: sha512 - get_checksum: yes - register: kafka_download_stat - -- name: Display sha of archive - debug: - msg: "Kafka SHA512: {{ kafka_download_stat.stat.checksum }}" +- name: Install Java package + package: + name: "openjdk-8-jre-headless" + state: present + when: ansible_os_family == "Debian" -- name: Verify sha512 of archive before installation - fail: - msg: "File checksum is not correct." - when: kafka_download_stat.stat.checksum != specification.kafka_var.sha +- name: Set Kafka file name to install + set_fact: + kafka_file_name: "{{ specification.kafka_var.file_name }}" + +- name: Download Kafka binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ kafka_file_name }}" + +# - name: Check for Kafka package +# stat: +# path: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" +# register: kafka_check + +# - name: Fetch Kafka binary package +# get_url: +# url: "https://archive.apache.org/dist/kafka/{{ specification.kafka_var.version }}/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" +# dest: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" +# validate_certs: "{{ validate_certs | bool }}" +# when: not kafka_check.stat.exists + +# - name: Get sha512 sum of archive +# stat: +# path: "/tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz" +# checksum_algorithm: sha512 +# get_checksum: yes +# register: kafka_download_stat + +# - name: Display sha of archive +# debug: +# msg: "Kafka SHA512: {{ kafka_download_stat.stat.checksum }}" + +# - name: Verify sha512 of archive before installation +# fail: +# msg: "File checksum is not correct." +# when: kafka_download_stat.stat.checksum != specification.kafka_var.sha - name: Add Kafka's bin dir to the PATH copy: @@ -55,18 +70,6 @@ dest: "/etc/profile.d/kafka_path.sh" mode: 0755 -- name: Setup group - group: - name: "{{ specification.kafka_var.group }}" - system: yes - -- name: Setup user - user: - name: "{{ specification.kafka_var.user }}" - system: yes - group: "{{ specification.kafka_var.group }}" - shell: "/usr/sbin/nologin" - - name: Check for Kafka package stat: path: /opt/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}/bin/kafka-server-start.sh @@ -74,9 +77,9 @@ - name: Uncompress the Kafka tar unarchive: - copy: no + remote_src: yes creates: /opt/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }} - src: /tmp/kafka_{{ specification.kafka_var.scala.version }}-{{ specification.kafka_var.version }}.tgz + src: "{{ download_directory }}/{{ kafka_file_name }}" dest: /opt when: not kafka_package.stat.exists diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kafka_exporter/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kafka_exporter/tasks/main.yml index 68aa78aa3c..737e77e520 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kafka_exporter/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kafka_exporter/tasks/main.yml @@ -13,69 +13,37 @@ group: kafka_exporter createhome: false -- name: Download kafka_exporter binary to local folder - become: false - get_url: - url: "{{ specification.download_urls[ansible_architecture] }}" - dest: "{{ specification.download_directory }}/kafka_exporter.tar.gz" - validate_certs: "{{ validate_certs | bool }}" - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - delegate_to: localhost +- name: Set Kafka Exporter file name to install + set_fact: + exporter_file_name: "{{ specification.file_name }}" -- name: Get sha512 sum of archive - become: false - stat: - path: "{{ specification.download_directory }}/kafka_exporter.tar.gz" - checksum_algorithm: sha512 - get_checksum: yes - register: kafka_exporter_download_stat - delegate_to: localhost +- name: Download Kafka Exporter binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ exporter_file_name }}" -- name: Display sha of archive - debug: - msg: "Kafka Exporter SHA512: {{ kafka_exporter_download_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: kafka_exporter_download_stat.stat.checksum not in specification.download_shas - -- name: Ensure download directory exists - become: false - file: - path: "{{ specification.download_directory }}/kafka_exporter" - state: directory - delegate_to: localhost - -- name: Unpack kafka_exporter binary - become: false - unarchive: - src: "{{ specification.download_directory }}/kafka_exporter.tar.gz" - dest: "{{ specification.download_directory }}/kafka_exporter" - creates: "{{ specification.download_directory }}/kafka_exporter/kafka_exporter" - extra_opts: [--strip-components=1] - delegate_to: localhost - check_mode: false - -- name: Create /opt/kafka_exporter directories +- name: Create /opt/kafka_exporter directory become: yes file: path: "{{ item }}" recurse: yes owner: root - group: "kafka_exporter" + group: kafka_exporter mode: 0750 state: directory with_items: - /opt/kafka_exporter -- name: Propagate kafka_exporter binaries - copy: - src: "{{ specification.download_directory }}/kafka_exporter/kafka_exporter" - dest: "/opt/kafka_exporter/kafka_exporter" +- name: Unpack kafka_exporter binary + become: true + unarchive: + remote_src: yes + src: "{{ download_directory }}/{{ exporter_file_name }}" + dest: "/opt/kafka_exporter" + creates: "/opt/kafka_exporter/kafka_exporter" + extra_opts: [--strip-components=1] mode: 0755 owner: root group: kafka_exporter diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/Debian.yml index 080d942eb0..1be9d0e028 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/Debian.yml @@ -1,38 +1,6 @@ ---- -## Kibana - -- name: Package install - apt: - deb: "https://artifacts.elastic.co/downloads/kibana/kibana-oss-{{ specification.kibana_version }}-amd64.deb" - when: - - groups['kibana'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/kibana/kibana.yml - regexp: '^#elasticsearch.url: "http://localhost:9200"$' - replace: "elasticsearch.url: \"http://{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}:9200\"" - backup: no - when: - - groups['kibana'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/kibana/kibana.yml - regexp: '^#server.host: "localhost"$' - replace: "server.host: \"{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}\"" - backup: no - when: - - groups['kibana'][0] == inventory_hostname - -- include_tasks: setup-logging.yml - when: - - groups['kibana'][0] == inventory_hostname - -- name: Start kibana service - service: - name: kibana - state: started - enabled: yes - when: - - groups['kibana'][0] == inventory_hostname +- name: Install Kibana package + apt: + name: + - kibana-oss + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/RedHat.yml index 5df069aa66..c0664086d6 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/RedHat.yml @@ -1,44 +1,6 @@ ---- -## Kibana master - -- name: Run echo - shell: "echo 'I am kibana on RedHat'" - register: output - when: - - groups['kibana'][0] == inventory_hostname - -- name: Install the latest version of Kibana +- name: Install Kibana package yum: - name: "https://artifacts.elastic.co/downloads/kibana/kibana-oss-{{ specification.kibana_version }}-x86_64.rpm" - when: - - groups['kibana'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/kibana/kibana.yml - regexp: '^#elasticsearch.url: "http://localhost:9200"$' - replace: "elasticsearch.url: \"http://{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}:9200\"" - backup: no - when: - - groups['kibana'][0] == inventory_hostname - -- name: Replace with interface - replace: - path: /etc/kibana/kibana.yml - regexp: '^#server.host: "localhost"$' - replace: "server.host: \"{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}\"" - backup: no - when: - - groups['kibana'][0] == inventory_hostname - -- include_tasks: setup-logging.yml - when: - - groups['kibana'][0] == inventory_hostname - -- name: Start kibana service - service: - name: kibana - state: started - enabled: yes - when: - - groups['kibana'][0] == inventory_hostname + name: + - kibana-oss + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/main.yml index b7784c818f..0dd21b6e8b 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kibana/tasks/main.yml @@ -1,4 +1,33 @@ --- -## Elasticsearch master - - include_tasks: "{{ ansible_os_family }}.yml" + +- name: Replace with interface + replace: + path: /etc/kibana/kibana.yml + regexp: '^#elasticsearch.url: "http://localhost:9200"$' + replace: "elasticsearch.url: \"http://{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}:9200\"" + backup: no + when: + - groups['kibana'][0] == inventory_hostname + +- name: Replace with interface + replace: + path: /etc/kibana/kibana.yml + regexp: '^#server.host: "localhost"$' + replace: "server.host: \"{{ hostvars[groups['kibana'][0]]['ansible_default_ipv4']['address'] }}\"" + backup: no + when: + - groups['kibana'][0] == inventory_hostname + +- include_tasks: setup-logging.yml + when: + - groups['kibana'][0] == inventory_hostname + +- name: Start kibana service + service: + name: kibana + state: started + enabled: yes + when: + - groups['kibana'][0] == inventory_hostname + diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-Debian.yml index c68ed3d08a..54c4cc2abb 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-Debian.yml @@ -1,21 +1,9 @@ --- -- name: APT Key - apt_key: - url: https://packages.cloud.google.com/apt/doc/apt-key.gpg - state: present - -- name: Add kubernetes repository - apt_repository: - repo: deb http://apt.kubernetes.io/ kubernetes-xenial main - state: present - filename: kubernetes - - name: Install NFS package for Debian family apt: name: - nfs-common - update_cache: yes state: present - name: Install Kubernetes packages for Debian family @@ -25,5 +13,4 @@ - kubelet={{specification.version}}-00 - kubectl={{specification.version}}-00 - kubeadm={{specification.version}}-00 - update_cache: yes - state: present + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-RedHat.yml index ecb1493020..79d5b05bfb 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/install-packages-RedHat.yml @@ -1,14 +1,5 @@ --- - -- name: Add kubernetes repository - yum_repository: - name: kubernetes - description: Kubernetes - file: kubernetes - baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 - gpgcheck: yes - gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg - + - name: Install NFS package for RedHat family yum: name: @@ -20,8 +11,8 @@ yum: name: - kubernetes-cni-0.7.5-0 - - kubelet-{{specification.version}} - - kubectl-{{specification.version}} - - kubeadm-{{specification.version}} + - kubelet-{{specification.version}}-0 + - kubectl-{{specification.version}}-0 + - kubeadm-{{specification.version}}-0 update_cache: yes - state: present + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/load-image.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/load-image.yml new file mode 100644 index 0000000000..450fbcbbea --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/load-image.yml @@ -0,0 +1,35 @@ +--- +- name: Create tag name with local image registry + set_fact: + new_image_tag: "{{image_registry_address}}/{{ docker_image.name }}" + changed_when: false + +- name: Check if image is already loaded + shell: "docker images {{ new_image_tag }} --format {{ '{{' }}.ID{{ '}}' }}" + register: image_check + ignore_errors: true + changed_when: false + +- name: Load image if does not exists + block: + - name: Download file + include_role: + name: download + tasks_from: download_image + vars: + file_name: "{{ docker_image.file_name }}" + + - name: Load image {{ docker_image.name }} + become: yes + shell: "docker load --input {{ download_directory }}/{{ docker_image.file_name }}" + + - name: Tag image {{ docker_image.name }} with {{ new_image_tag }} + become: yes + shell: "docker tag {{ docker_image.name }} {{ new_image_tag }}" + + - name: Push image to registry {{ docker_image.name }} + become: yes + shell: "docker push {{ new_image_tag }}" + + when: + - image_check.stdout | length == 0 diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/main.yml index 8bf67323c0..fa57d01c90 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_common/tasks/main.yml @@ -1,2 +1,34 @@ --- + - include_tasks: install-packages.yml + +- name: Include load-image.yml + include_tasks: "load-image.yml" + vars: + docker_image: "{{ item }}" + loop: "{{ specification.images_to_load }}" + when: not custom_image_registry_address + +- name: Enable ip forwarding + sysctl: + name: net.ipv4.ip_forward + value: "1" + state: present + reload: yes + +- name: Check if bridge-nf-call-iptables key exists + command: "sysctl net.bridge.bridge-nf-call-iptables" + failed_when: false + changed_when: false + register: sysctl_bridge_nf_call_iptables + +- name: Enable bridge-nf-call tables + sysctl: + name: "{{ item }}" + state: present + value: "1" + reload: yes + when: sysctl_bridge_nf_call_iptables.rc == 0 + with_items: + - net.bridge.bridge-nf-call-iptables + - net.bridge.bridge-nf-call-ip6tables \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/calico.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/calico.yml index 70647e171e..cbac0895b0 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/calico.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/calico.yml @@ -1,11 +1,13 @@ --- -- name: Copy calico config - copy: - src: calico.yml - dest: /home/{{ admin_user.name }}/ + +- name: Create calico deployment + template: + dest: "/home/{{ admin_user.name }}/calico.yml" + src: calico.yml.j2 owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" + - name: Apply calico definition shell: kubectl apply --kubeconfig=/home/{{ admin_user.name }}/.kube/config -f /home/{{ admin_user.name }}/calico.yml become_user: "{{ admin_user.name }}" \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/flannel.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/flannel.yml index 53f02c5d55..5ba8167b50 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/flannel.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/cni-plugins/flannel.yml @@ -1,8 +1,8 @@ --- -- name: Copy flannel config - copy: - src: kube-flannel.yml - dest: /home/{{ admin_user.name }}/ +- name: Create flannel deployment + template: + dest: "/home/{{ admin_user.name }}/kube-flannel.yml" + src: kube-flannel.yml.j2 owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/single-master.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/single-master.yml index 9d2a095aeb..f7e98b77e1 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/single-master.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/tasks/single-master.yml @@ -8,9 +8,7 @@ path: /etc/kubernetes/manifests/kube-apiserver.yaml register: kube -- name: kubeadm config images pull --kubernetes-version={{ specification.version }} - shell: "kubeadm config images pull --kubernetes-version={{ specification.version }}" - # when: not kube.stat.exists +# TODO ensure there are images in repo - if not, fail - name: Creates directory file: @@ -55,10 +53,10 @@ owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" -- name: Copy dashboard yaml - copy: - src: kubernetes-dashboard.yml - dest: /home/{{ admin_user.name }}/ +- name: Create dashboard deployment + template: + dest: "/home/{{ admin_user.name }}/kubernetes-dashboard.yml" + src: kubernetes-dashboard.yml.j2 owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" @@ -83,10 +81,10 @@ owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" -- name: Copy coredns-config.yml - copy: - src: coredns-config.yml - dest: /home/{{ admin_user.name }}/ +- name: Create CoreDNS deployment + template: + dest: "/home/{{ admin_user.name }}/coredns-config.yml" + src: coredns-config.yml.j2 owner: "{{ admin_user.name }}" group: "{{ admin_user.name }}" diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/calico.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/calico.yml.j2 similarity index 98% rename from core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/calico.yml rename to core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/calico.yml.j2 index f1f29e13a7..54385980b3 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/calico.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/calico.yml.j2 @@ -515,7 +515,7 @@ spec: # It can be deleted if this is a fresh installation, or if you have already # upgraded to use calico-ipam. - name: upgrade-ipam - image: calico/cni:v3.8.0 + image: {{ image_registry_address }}/calico/cni:v3.8.1 command: ["/opt/cni/bin/calico-ipam", "-upgrade"] env: - name: KUBERNETES_NODE_NAME @@ -535,7 +535,7 @@ spec: # This container installs the CNI binaries # and CNI network config file on each node. - name: install-cni - image: calico/cni:v3.8.0 + image: {{ image_registry_address }}/calico/cni:v3.8.1 command: ["/install-cni.sh"] env: # Name of the CNI config file to create. @@ -569,7 +569,7 @@ spec: # Adds a Flex Volume Driver that creates a per-pod Unix Domain Socket to allow Dikastes # to communicate with Felix over the Policy Sync API. - name: flexvol-driver - image: calico/pod2daemon-flexvol:v3.8.0 + image: {{ image_registry_address }}/calico/pod2daemon-flexvol:v3.8.1 volumeMounts: - name: flexvol-driver-host mountPath: /host/driver @@ -578,7 +578,7 @@ spec: # container programs network policy and routes on each # host. - name: calico-node - image: calico/node:v3.8.0 + image: {{ image_registry_address }}/calico/node:v3.8.1 env: # Use Kubernetes API as the backing datastore. - name: DATASTORE_TYPE @@ -752,7 +752,7 @@ spec: priorityClassName: system-cluster-critical containers: - name: calico-kube-controllers - image: calico/kube-controllers:v3.8.0 + image: {{ image_registry_address }}/calico/kube-controllers:v3.8.1 env: # Choose which controllers to run. - name: ENABLED_CONTROLLERS diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/canal-deployment.yml.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/canal-deployment.yml.j2 index 8717258e53..a41db4eed1 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/canal-deployment.yml.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/canal-deployment.yml.j2 @@ -399,7 +399,7 @@ spec: # This container installs the CNI binaries # and CNI network config file on each node. - name: install-cni - image: calico/cni:v3.8.1 + image: {{ image_registry_address }}/calico/cni:v3.8.1 command: ["/install-cni.sh"] env: # Name of the CNI config file to create. @@ -427,7 +427,7 @@ spec: # Adds a Flex Volume Driver that creates a per-pod Unix Domain Socket to allow Dikastes # to communicate with Felix over the Policy Sync API. - name: flexvol-driver - image: calico/pod2daemon-flexvol:v3.8.1 + image: {{ image_registry_address }}/calico/pod2daemon-flexvol:v3.8.1 volumeMounts: - name: flexvol-driver-host mountPath: /host/driver @@ -436,7 +436,7 @@ spec: # container programs network policy and routes on each # host. - name: calico-node - image: calico/node:v3.8.1 + image: {{ image_registry_address }}/calico/node:v3.8.1 env: # Use Kubernetes API as the backing datastore. - name: DATASTORE_TYPE @@ -520,7 +520,7 @@ spec: # This container runs flannel using the kube-subnet-mgr backend # for allocating subnets. - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0 + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0 command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr" ] securityContext: privileged: true diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/coredns-config.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/coredns-config.yml.j2 similarity index 98% rename from core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/coredns-config.yml rename to core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/coredns-config.yml.j2 index 1e7849e87d..6760d46561 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/coredns-config.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/coredns-config.yml.j2 @@ -103,7 +103,7 @@ spec: beta.kubernetes.io/os: linux containers: - name: coredns - image: coredns/coredns:1.5.0 + image: {{ image_registry_address }}/coredns/coredns:1.5.0 imagePullPolicy: IfNotPresent resources: limits: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kube-flannel.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kube-flannel.yml.j2 similarity index 93% rename from core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kube-flannel.yml rename to core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kube-flannel.yml.j2 index 859d55bb61..ad51445749 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kube-flannel.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kube-flannel.yml.j2 @@ -154,7 +154,7 @@ spec: serviceAccountName: flannel initContainers: - name: install-cni - image: quay.io/coreos/flannel:v0.11.0-amd64 + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-amd64 command: - cp args: @@ -168,7 +168,7 @@ spec: mountPath: /etc/kube-flannel/ containers: - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0-amd64 + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-amd64 command: - /opt/bin/flanneld args: @@ -234,7 +234,7 @@ spec: serviceAccountName: flannel initContainers: - name: install-cni - image: quay.io/coreos/flannel:v0.11.0-arm64 + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-arm64 command: - cp args: @@ -248,7 +248,7 @@ spec: mountPath: /etc/kube-flannel/ containers: - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0-arm64 + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-arm64 command: - /opt/bin/flanneld args: @@ -314,7 +314,7 @@ spec: serviceAccountName: flannel initContainers: - name: install-cni - image: quay.io/coreos/flannel:v0.11.0-arm + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-arm command: - cp args: @@ -328,7 +328,7 @@ spec: mountPath: /etc/kube-flannel/ containers: - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0-arm + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-arm command: - /opt/bin/flanneld args: @@ -394,7 +394,7 @@ spec: serviceAccountName: flannel initContainers: - name: install-cni - image: quay.io/coreos/flannel:v0.11.0-ppc64le + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-ppc64le command: - cp args: @@ -408,7 +408,7 @@ spec: mountPath: /etc/kube-flannel/ containers: - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0-ppc64le + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-ppc64le command: - /opt/bin/flanneld args: @@ -474,7 +474,7 @@ spec: serviceAccountName: flannel initContainers: - name: install-cni - image: quay.io/coreos/flannel:v0.11.0-s390x + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-s390x command: - cp args: @@ -488,7 +488,7 @@ spec: mountPath: /etc/kube-flannel/ containers: - name: kube-flannel - image: quay.io/coreos/flannel:v0.11.0-s390x + image: {{ image_registry_address }}/quay.io/coreos/flannel:v0.11.0-s390x command: - /opt/bin/flanneld args: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubeadm-config.yml.j2 b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubeadm-config.yml.j2 index aa3a2f978d..9d4ee08580 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubeadm-config.yml.j2 +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubeadm-config.yml.j2 @@ -20,5 +20,12 @@ networking: dnsDomain: {{ specification.advanced.networking.dnsDomain }} podSubnet: {{ specification.advanced.networking.podSubnet }} serviceSubnet: {{ specification.advanced.networking.serviceSubnet }} -imageRepository: {{ specification.advanced.imageRepository }} + +{% if custom_image_registry_address|length == 0 %} +imageRepository: {{ image_registry_address }}/{{ specification.advanced.imageRepository }} +{% else %} +imageRepository: {{ custom_image_registry_address }}/{{ specification.advanced.imageRepository }} +{% endif %} + + certificatesDir: {{ specification.advanced.certificatesDir }} \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kubernetes-dashboard.yml b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubernetes-dashboard.yml.j2 similarity index 97% rename from core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kubernetes-dashboard.yml rename to core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubernetes-dashboard.yml.j2 index a33a5c2515..fea5d584a7 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/files/kubernetes-dashboard.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/kubernetes_master/templates/kubernetes-dashboard.yml.j2 @@ -188,7 +188,7 @@ spec: spec: containers: - name: kubernetes-dashboard - image: kubernetesui/dashboard:v2.0.0-beta1 + image: {{ image_registry_address }}/kubernetesui/dashboard:v2.0.0-beta1 imagePullPolicy: Always ports: - containerPort: 8443 @@ -263,7 +263,7 @@ spec: spec: containers: - name: kubernetes-metrics-scraper - image: kubernetesui/metrics-scraper:v1.0.0 + image: {{ image_registry_address }}/kubernetesui/metrics-scraper:v1.0.0 ports: - containerPort: 8000 protocol: TCP diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/node_exporter/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/node_exporter/tasks/main.yml index f4af0ccd78..03c90b08a2 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/node_exporter/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/node_exporter/tasks/main.yml @@ -13,53 +13,16 @@ group: node_exporter createhome: false -- name: Ensure download directory exists - become: false - file: - path: "{{ specification.download_directory }}/node_exporter" - state: directory - delegate_to: localhost - -# TODO: Checking download node_exporter -- name: Download node_exporter binary to local folder - become: false - get_url: - url: "{{ specification.download_urls[ansible_architecture] }}" - dest: "{{ specification.download_directory }}/node_exporter.tar.gz" - validate_certs: "{{ validate_certs | bool}}" - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - delegate_to: localhost - -- name: Get sha512 sum of archive - become: false - stat: - path: "{{ specification.download_directory }}/node_exporter.tar.gz" - checksum_algorithm: sha512 - get_checksum: yes - register: node_exporter_stat - delegate_to: localhost +- name: Set Node Exporter file name to install + set_fact: + exporter_file_name: "{{ specification.file_name }}" -- name: Display sha of archive - debug: - msg: "Node Exporter SHA512: {{ node_exporter_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: node_exporter_stat.stat.checksum not in specification.download_shas - -- name: Unpack node_exporter binary - become: false - unarchive: - src: "{{ specification.download_directory }}/node_exporter.tar.gz" - dest: "{{ specification.download_directory }}/node_exporter" - creates: "{{ specification.download_directory }}/node_exporter/node_exporter" - extra_opts: [--strip-components=1] - delegate_to: localhost - check_mode: false +- name: Download Node Exporter binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ exporter_file_name }}" - name: Create /opt/node_exporter directories become: yes @@ -73,10 +36,14 @@ with_items: - /opt/node_exporter -- name: Propagate node_exporter binaries - copy: - src: "{{ specification.download_directory }}/node_exporter/node_exporter" - dest: "/opt/node_exporter/node_exporter" +- name: Unpack node_exporter binary + become: true + unarchive: + remote_src: yes + src: "{{ download_directory }}/{{ exporter_file_name }}" + dest: "/opt/node_exporter" + creates: "/opt/node_exporter/node_exporter" + extra_opts: [--strip-components=1] mode: 0755 owner: root group: node_exporter diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/Debian.yml index aa36549a56..53991a06bf 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/Debian.yml @@ -8,7 +8,7 @@ - postgresql-contrib-10 - python-psycopg2 # required for postresql ansible management update_cache: yes - state: present + state: present - name: Changing pg_hba.conf replace: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml index 8e5d187a0e..e15fc5902b 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/RedHat.yml @@ -1,31 +1,5 @@ --- # Postgresql Red Hat family of specific tasks - -- name: Check if repository file exists - stat: - path: /etc/yum.repos.d/redhat-rhui.repo - register: rhui_exist - when: - - specification.provider == "aws" - -- name: Check if Software Collections repository on EC2 exists - shell: grep -c -i rhui-REGION-rhel-server-rhscl /etc/yum.repos.d/redhat-rhui.repo - register: sc_repo_count - failed_when: "sc_repo_count.rc == 2" - when: - - specification.provider == "aws" - - rhui_exist - -- name: Enable Software Collections on EC2 - ini_file: - dest: /etc/yum.repos.d/redhat-rhui.repo - section: rhui-REGION-rhel-server-rhscl - option: enabled - value: 1 - when: - - specification.provider == "aws" - - sc_repo_count.stdout|int == 1 - - name: Install postgresql family packages yum: name: diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/main.yml b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/main.yml index 51bc61e23d..e47a430997 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/main.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/postgresql/tasks/main.yml @@ -1,5 +1,4 @@ --- # Common main as the entry point - - include_tasks: "{{ ansible_os_family }}.yml" diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install-alertmanager.yml b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install-alertmanager.yml index fb44e8a4cc..fcf6f8ee0c 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install-alertmanager.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install-alertmanager.yml @@ -1,56 +1,23 @@ --- -- name: Ensure download directory exists - become: false - file: - path: "{{ specification.download_directory }}/alert_manager_libraries" - state: directory - delegate_to: localhost - -# TODO: Checking alertmanager -- name: Download Alertmanager binary to local folder - become: false - get_url: - url: "{{ specification.alerts.alertmanager.download_urls[ansible_architecture] }}" - dest: "{{ specification.download_directory }}/alertmanager.tar.gz" - validate_certs: "{{ validate_certs | bool}}" - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - delegate_to: localhost - -- name: Get sha512 sum of archive - become: false - stat: - path: "{{ specification.download_directory }}/alertmanager.tar.gz" - checksum_algorithm: sha512 - get_checksum: yes - register: alertmanager_download_stat - delegate_to: localhost - -- name: Display sha of archive - debug: - msg: "Alertmanager SHA512: {{ alertmanager_download_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: alertmanager_download_stat.stat.checksum not in specification.alerts.alertmanager.download_shas - -- name: Unpack Alertmanager binary - become: false +- name: Set Prometheus file name to install + set_fact: + binary_file_name: "{{ specification.alerts.alertmanager.file_name }}" + +- name: Download Prometheus binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ binary_file_name }}" + +- name: Unpack AlertManager binary + become: true unarchive: - src: "{{ specification.download_directory }}/alertmanager.tar.gz" - dest: "{{ specification.download_directory }}/alert_manager_libraries" - creates: "{{ specification.download_directory }}/alert_manager_libraries/alertmanager" + remote_src: yes + src: "{{ download_directory }}/{{ binary_file_name }}" + dest: "/usr/local/bin" + creates: "/usr/local/bin/alertmanager" extra_opts: [--strip-components=1] - delegate_to: localhost - check_mode: false - -- name: Propagate Alertmanager - copy: - src: "{{ specification.download_directory }}/alert_manager_libraries/alertmanager" - dest: "/usr/local/bin/alertmanager" mode: 0755 owner: root group: prometheus diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install.yml b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install.yml index 3d912cd0a1..b54acd3b81 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/install.yml @@ -34,89 +34,118 @@ - "{{ specification.config_directory }}/rules" - "{{ specification.config_directory }}/file_sd" -- name: Ensure download directory exists - become: false - file: - path: "{{ specification.download_directory }}/prometheus_binaries" - state: directory - delegate_to: localhost - -# TODO: Checking prometheus -- name: Download Prometheus binary to local folder - become: false - get_url: - url: "{{ specification.download_urls[ansible_architecture] }}" - dest: "{{ specification.download_directory }}/prometheus.tar.gz" - validate_certs: "{{ validate_certs | bool}}" - register: _download_archive - until: _download_archive is succeeded - retries: 5 - delay: 2 - delegate_to: localhost - -- name: Get sha512 sum of archive - become: false - stat: - path: "{{ specification.download_directory }}/prometheus.tar.gz" - checksum_algorithm: sha512 - get_checksum: yes - register: prometheus_download_stat - delegate_to: localhost - -- name: Display sha of archive - debug: - msg: "Prometheus SHA512: {{ prometheus_download_stat.stat.checksum }}" - -- name: Verify sha512 of archive before installation. - fail: - msg: "File checksum is not correct." - when: prometheus_download_stat.stat.checksum not in specification.download_shas +# - name: Ensure download directory exists +# become: false +# file: +# path: "{{ specification.download_directory }}/prometheus_binaries" +# state: directory +# delegate_to: localhost + +# # TODO: Checking prometheus +# - name: Download Prometheus binary to local folder +# become: false +# get_url: +# url: "{{ specification.download_urls[ansible_architecture] }}" +# dest: "{{ specification.download_directory }}/prometheus.tar.gz" +# validate_certs: "{{ validate_certs | bool}}" +# register: _download_archive +# until: _download_archive is succeeded +# retries: 5 +# delay: 2 +# delegate_to: localhost + +# - name: Get sha512 sum of archive +# become: false +# stat: +# path: "{{ specification.download_directory }}/prometheus.tar.gz" +# checksum_algorithm: sha512 +# get_checksum: yes +# register: prometheus_download_stat +# delegate_to: localhost + +# - name: Display sha of archive +# debug: +# msg: "Prometheus SHA512: {{ prometheus_download_stat.stat.checksum }}" + +# - name: Verify sha512 of archive before installation. +# fail: +# msg: "File checksum is not correct." +# when: prometheus_download_stat.stat.checksum not in specification.download_shas + +# - name: Unpack Prometheus binary +# become: false +# unarchive: +# src: "{{ specification.download_directory }}/prometheus.tar.gz" +# dest: "{{ specification.download_directory }}/prometheus_binaries" +# creates: "{{ specification.download_directory }}/prometheus_binaries/prometheus" +# extra_opts: [--strip-components=1] +# delegate_to: localhost +# check_mode: false + +# - name: Propagate Prometheus and promtool binaries +# copy: +# src: "{{ specification.download_directory }}/prometheus_binaries/{{ item }}" +# dest: "/usr/local/bin/{{ item }}" +# mode: 0755 +# owner: root +# group: prometheus +# with_items: +# - prometheus +# - promtool +# check_mode: false +# notify: +# - restart prometheus + +# - name: Propagate console libraries templates +# copy: +# src: "{{ specification.download_directory }}/prometheus_binaries/{{ item }}" +# dest: "{{ specification.config_directory }}/{{ item }}/" +# mode: 0755 +# with_items: +# - console_libraries +# - consoles +# check_mode: false +# notify: +# - restart prometheus + +# - name: Remove prometheus binaries from old location +# file: +# path: "{{ item }}" +# state: absent +# with_items: +# - /opt/prometheus/prometheus +# - /opt/prometheus/promtool +# - /opt/prometheus + +- name: Set Prometheus file name to install + set_fact: + binary_file_name: "{{ specification.file_name }}" + +- name: Package + debug: msg="{{ binary_file_name }}" + +- name: Download Prometheus binaries + include_role: + name: download + tasks_from: download_file + vars: + file_name: "{{ binary_file_name }}" - name: Unpack Prometheus binary - become: false + become: true unarchive: - src: "{{ specification.download_directory }}/prometheus.tar.gz" - dest: "{{ specification.download_directory }}/prometheus_binaries" - creates: "{{ specification.download_directory }}/prometheus_binaries/prometheus" + src: "{{ download_directory }}/{{ binary_file_name }}" + remote_src: yes + dest: "/usr/local/bin" + creates: "/usr/local/bin/prometheus" extra_opts: [--strip-components=1] - delegate_to: localhost - check_mode: false - -- name: Propagate Prometheus and promtool binaries - copy: - src: "{{ specification.download_directory }}/prometheus_binaries/{{ item }}" - dest: "/usr/local/bin/{{ item }}" mode: 0755 owner: root group: prometheus - with_items: - - prometheus - - promtool check_mode: false notify: - restart prometheus -- name: Propagate console libraries templates - copy: - src: "{{ specification.download_directory }}/prometheus_binaries/{{ item }}" - dest: "{{ specification.config_directory }}/{{ item }}/" - mode: 0755 - with_items: - - console_libraries - - consoles - check_mode: false - notify: - - restart prometheus - -- name: Remove prometheus binaries from old location - file: - path: "{{ item }}" - state: absent - with_items: - - /opt/prometheus/prometheus - - /opt/prometheus/promtool - - /opt/prometheus - - name: Create systemd service unit template: src: prometheus.service.j2 diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/preflight.yml b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/preflight.yml index a91df64166..39d5984f3f 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/preflight.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/prometheus/tasks/preflight.yml @@ -84,12 +84,12 @@ when: prometheus_version == "latest" #commented out due to issues when ran on macOS -#- name: "Get checksum for {{ go_arch_map[ansible_architecture] | default(ansible_architecture) }} architecture" +#- name: "Get checksum for {{ shared.architecture_map[ansible_architecture] | default(ansible_architecture) }} architecture" # set_fact: # prometheus_checksum: "{{ item.split(' ')[0] }}" # with_items: # - "{{ lookup('url', 'https://github.com/prometheus/prometheus/releases/download/v' + prometheus_version + '/sha256sums.txt', wantlist=True) | list }}" -# when: "('linux-' + (go_arch_map[ansible_architecture] | default(ansible_architecture)) + '.tar.gz') in item" +# when: "('linux-' + (shared.architecture_map[ansible_architecture] | default(ansible_architecture)) + '.tar.gz') in item" - name: Get systemd version shell: systemctl --version | awk '$1 == "systemd" {print $2}' diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/Debian.yml b/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/Debian.yml index 6b2d677b42..97c0596e19 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/Debian.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/Debian.yml @@ -1,28 +1,11 @@ ---- -- name: Get APT Key - apt_key: - url: https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc - state: present - -- name: Add Erlang repository - apt_repository: - repo: deb http://dl.bintray.com/rabbitmq-erlang/debian bionic erlang-21.x - state: present - filename: bintray.erlang.list - update_cache: true - -- name: Install dependencies for RabbitMQ - apt: - update_cache: true +- name: Install Rabitmq packages + apt: name: - init-system-helpers - socat - erlang-nox - adduser - logrotate - state: present - -- name: Install RabbitMQ package - apt: - deb: "https://github.com/rabbitmq/rabbitmq-server/releases/download/v{{ specification.version }}/rabbitmq-server_{{ specification.version }}-1_all.deb" - state: present + - rabbitmq-server + update_cache: yes + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/RedHat.yml b/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/RedHat.yml index a4dab851a2..9dda9c0283 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/RedHat.yml +++ b/core/src/epicli/data/common/ansible/playbooks/roles/rabbitmq/tasks/RedHat.yml @@ -1,19 +1,8 @@ ---- -## RabbitMQ Red Hat - -- name: Install Erlang package - yum: - name: "https://github.com/rabbitmq/erlang-rpm/releases/download/v21.2.2/erlang-21.2.2-1.el7.centos.x86_64.rpm" - state: present - -- name: Install dependency for RabbitMQ +- name: Install Rabbitmq packages yum: name: - socat - logrotate - state: present - -- name: Install RabbitMQ package - yum: - name: "https://github.com/rabbitmq/rabbitmq-server/releases/download/v{{ specification.version }}/rabbitmq-server-{{ specification.version }}-1.el7.noarch.rpm" - state: present + - erlang-21.3.* # order matters, check RabbitMQ/Erlang version compatibility matrix before modification + - rabbitmq-server-3.7.10 + state: present \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/add-epirepo-client.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/add-epirepo-client.sh new file mode 100644 index 0000000000..466f42efc8 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/add-epirepo-client.sh @@ -0,0 +1,7 @@ +#!/bin/bash -eu + +REPOSITORY_URL=$1 + +echo "deb [trusted=yes] $REPOSITORY_URL/packages ./" > /etc/apt/sources.list.d/epirepo.list + +apt update \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/create-enabled-system-repos-list.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/create-enabled-system-repos-list.sh new file mode 100644 index 0000000000..dcdc4209c5 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/create-enabled-system-repos-list.sh @@ -0,0 +1,7 @@ +#!/bin/bash -eu + +REPOS_BACKUP_FILE=/var/tmp/enabled-system-repos.tar + +if [ ! -f "$REPOS_BACKUP_FILE" ]; then + tar --ignore-failed-read --absolute-names -cvpf ${REPOS_BACKUP_FILE} /etc/apt/sources.list /etc/apt/sources.list.d/ 2>&1 +fi diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-epirepo-client.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-epirepo-client.sh new file mode 100644 index 0000000000..e6b85d9b5e --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-epirepo-client.sh @@ -0,0 +1,5 @@ +#!/bin/bash -eu + +rm -f /etc/apt/sources.list.d/epirepo.list +apt-get clean +apt update \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-system-repos.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-system-repos.sh new file mode 100644 index 0000000000..a87d67c23a --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/disable-system-repos.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +REPOS_BACKUP_FILE=/var/tmp/enabled-system-repos.tar + +if [ -f "$REPOS_BACKUP_FILE" ]; then + rm -f /etc/apt/sources.list /etc/apt/sources.list.d/* +else + echo "${REPOS_BACKUP_FILE} file not found. You don't seem to have a backup of the repositories. Cowardly refusing to delete system files." +fi diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/enable-system-repos.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/enable-system-repos.sh new file mode 100644 index 0000000000..12fa5c1aba --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/Debian/enable-system-repos.sh @@ -0,0 +1,5 @@ +#!/bin/bash -eu + +REPOS_BACKUP_FILE=/var/tmp/enabled-system-repos.tar + +tar -C / --absolute-name -xvf ${REPOS_BACKUP_FILE} 2>&1 \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/add-epirepo-client.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/add-epirepo-client.sh new file mode 100644 index 0000000000..e6c21587e2 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/add-epirepo-client.sh @@ -0,0 +1,19 @@ +#!/bin/bash -eu + +REPOSITORY_URL=$1 + +CURL_CMD="curl --head --location --connect-timeout 30 --silent --show-error $REPOSITORY_URL" +CURL_OUTPUT=$($CURL_CMD 2>&1) || { echo "Command failed: $CURL_CMD"; echo "Output was: $CURL_OUTPUT"; exit 2; } + +egrep 'HTTP/.{1,3} 200 OK' <<< "$CURL_OUTPUT" || { echo "HTTP 200 status code not found"; exit 3; } + +cat << EOF > /etc/yum.repos.d/epirepo.repo +[epirepo] +name=epirepo +baseurl=$REPOSITORY_URL/packages/ +enabled=1 +gpgcheck=0 +EOF + +yum makecache fast +yum repolist \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/create-enabled-system-repos-list.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/create-enabled-system-repos-list.sh new file mode 100644 index 0000000000..34d2791bf4 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/create-enabled-system-repos-list.sh @@ -0,0 +1,8 @@ +#!/bin/bash -eu + +ENABLED_REPOS_LIST_FILE=/var/tmp/enabled-system-repos.txt + +if [ ! -f "$ENABLED_REPOS_LIST_FILE" ]; then + # 'yum repoinfo' or 'yum repolist -v' not used since they may require Internet access, even with --cacheonly + yum --cacheonly repolist enabled | awk '/^$/ {next}; /repo id/ {f=1; next}; /^repolist/ {f=0}; f {sub(/\/.*/,""); print $1}' > $ENABLED_REPOS_LIST_FILE +fi diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-epirepo-client.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-epirepo-client.sh new file mode 100644 index 0000000000..24124a975a --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-epirepo-client.sh @@ -0,0 +1,5 @@ +#!/bin/bash -eu + +yum-config-manager --disable epirepo +yum clean all --disablerepo='*' --enablerepo=epirepo +yum repolist \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-system-repos.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-system-repos.sh new file mode 100644 index 0000000000..d50a666400 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/disable-system-repos.sh @@ -0,0 +1,16 @@ +#!/bin/bash -eu + +REPOS_LIST_FILE=/var/tmp/enabled-system-repos.txt +YUM_REPOS_BACKUP_FILE=/etc/yum.repos.d/yum.repos.d-epi-backup.tar + +if yum-config-manager --version > /dev/null 2>&1; then + cat $REPOS_LIST_FILE | while read repository + do + echo "Disabling repository: $repository" + yum-config-manager --disable $repository + done +elif [ ! -f $YUM_REPOS_BACKUP_FILE ]; then # for hosts where yum-utils is not available + echo "Disabling all yum repositories by backup & remove files in /etc/yum.repos.d" + tar -cv --verify --directory="/" --file=$YUM_REPOS_BACKUP_FILE /etc/yum.repos.d && + rm -f /etc/yum.repos.d/*.repo +fi \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/enable-system-repos.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/enable-system-repos.sh new file mode 100644 index 0000000000..74bc995f1f --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/client/RedHat/enable-system-repos.sh @@ -0,0 +1,22 @@ +#!/bin/bash -eu + +REPOS_LIST_FILE=/var/tmp/enabled-system-repos.txt +YUM_REPOS_BACKUP_FILE=/etc/yum.repos.d/yum.repos.d-epi-backup.tar + +if [ -f $YUM_REPOS_BACKUP_FILE ]; then # hosts without yum-config-manager + echo "Restoring /etc/yum.repos.d/*.repo from: $YUM_REPOS_BACKUP_FILE" + if tar -xv --file $YUM_REPOS_BACKUP_FILE --directory /etc/yum.repos.d \ + --strip-components=2 etc/yum.repos.d/*.repo; then + echo "yum repositories restored" + rm -f $YUM_REPOS_BACKUP_FILE + else + echo "Extracting tar failed: $YUM_REPOS_BACKUP_FILE" + exit 2 + fi +else # hosts with yum-config-manager + cat $REPOS_LIST_FILE | while read repository + do + echo "Enabling repository: $repository" + yum-config-manager --enable $repository + done +fi \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh new file mode 100644 index 0000000000..55b620c3f9 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh @@ -0,0 +1,611 @@ +#!/usr/bin/env bash + +# VERSION 1.0.3 + +# NOTE: You can run only one instance of this script, new instance kills the previous one +# This limitation is for Ansible + +set -euo pipefail + +# === Functions (in alphabetical order) === + +# params: +add_repo() { + local repo_id="$1" + local repo_url="$2" + + if ! is_repo_enabled "$repo_id"; then + echol "Adding repository: $repo_id" + yum-config-manager --add-repo "$repo_url" || + exit_with_error "Command failed: yum-config-manager --add-repo \"$repo_url\"" + echo "$repo_id.repo" >> "$ADDED_REPOSITORIES_FILE_PATH" + # to accept import of GPG keys + yum -y repolist > /dev/null || + exit_with_error "Command failed: yum -y repolist" + fi +} + +# params: +add_repo_as_file() { + local repo_id="$1" + local config_file_contents="$2" + local config_file_name="$repo_id.repo" + + if ! is_repo_enabled "$repo_id"; then + echol "Adding repository: $repo_id" + cat <<< "$config_file_contents" > "/etc/yum.repos.d/$config_file_name" || + exit_with_error "Function add_repo_as_file failed for repo: $repo_id" + echo "$config_file_name" >> "$ADDED_REPOSITORIES_FILE_PATH" + # to accept import of GPG keys + yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" + fi +} + +# params: ... [path_N_to_backup] +backup_files() { + local backup_file_path="$1" + shift + local paths_to_backup="$@" + + # --directory='/' is for tar --verify + tar --create --verbose --verify --directory="/" --file="$backup_file_path" $paths_to_backup +} + +# params: +create_directory() { + local dir_path="$1" + + if [[ -d "$dir_path" ]]; then + echol "Directory $dir_path already exists" + else + echol "Creating directory: $dir_path" + mkdir -p "$dir_path" || exit_with_error "Command failed: mkdir -p \"$dir_path\"" + fi +} + +# params: +download_file() { + local file_url="$1" + local dest_dir="$2" + + local file_name=$(basename "$file_url") + local dest_path="$dest_dir/$file_name" + + # wget with --timestamping sometimes failes on AWS with ERROR 403: Forbidden + # so we remove existing file to overwrite it, to be optimized + [[ ! -f $dest_path ]] || remove_file "$dest_path" + + echol "Downloading file: $file" + + wget --no-verbose --directory-prefix="$dest_dir" "$file_url" || + exit_with_error "Command failed: wget --no-verbose --directory-prefix=\"$dest_dir\" \"$file_url\"" +} + +# params: +download_image() { + local image_name="$1" + local dest_dir="$2" + + local splited_image=(${image_name//:/ }) + local repository=${splited_image[0]} + local tag=${splited_image[1]} + local repo_basename=$(basename -- "$repository") + local dest_path="${dest_dir}/${repo_basename}-${tag}.tar" + + if [[ -f $dest_path ]]; then + echol "Image file: "$dest_path" already exists. Skipping..." + else + # use temporary file for downloading to be safe from sudden interruptions (network, ctrl+c) + local tmp_file_path=$(mktemp) + local skopeo_cmd="$SKOPEO_BIN --insecure-policy copy docker://$image_name docker-archive:$tmp_file_path:$repository:$tag" + echol "Downloading image: $image" + { $skopeo_cmd && chmod 644 $tmp_file_path && mv $tmp_file_path $dest_path; } || + exit_with_error "skopeo failed, command was: $skopeo_cmd && chmod 644 $tmp_file_path && mv $tmp_file_path $dest_path" + fi +} + +# params: ... [package_N] +download_packages() { + local dest_dir="$1" + shift + local packages="$@" + + if [[ -n $packages ]]; then + # when using --archlist=x86_64 yumdownloader (yum-utils-1.1.31-52) also downloads i686 packages + yumdownloader --quiet --archlist=x86_64 --exclude='*i686' --destdir="$dest_dir" $packages || + exit_with_error "yumdownloader failed for: $packages" + fi +} + +echol() { + echo -e "$@" + if [[ $CREATE_LOGFILE == 'yes' ]]; then + local timestamp=$(date +"%b %e %H:%M:%S") + echo -e "${timestamp}: $@" >> "$LOG_FILE_PATH" + fi +} + +# params: +enable_repo() { + local repo_id="$1" + + if ! yum repolist enabled | grep --quiet "$repo_id"; then + echol "Enabling repository: $repo_id" + yum-config-manager --enable "$repo_id" || + exit_with_error "Command failed: yum-config-manager --enable \"$repo_id\"" + fi +} + +exit_with_error() { + echol "ERROR: $1" + exit 1 +} + +# params: +get_package_dependencies_with_arch() { + # $1 reserved for result + local package="$2" + + local query_output=$(repoquery --requires --resolve --queryformat '%{name}.%{arch}' --archlist=x86_64,noarch "$package") || + exit_with_error "repoquery failed for dependencies of package: $package with exit code: $?, output was: $query_output" + + if [[ -z $query_output ]]; then + echol "No dependencies found for package: $package" + elif grep --ignore-case --perl-regexp '\b(? +get_package_with_version_arch() { + # $1 reserved for result + local package="$2" + + local query_output=$(repoquery --queryformat '%{ui_nevra}' --archlist=x86_64,noarch "$package") || + exit_with_error "repoquery failed for package: $package with exit code: $?, output was: $query_output" + + # yumdownloader doesn't set error code if repoquery returns empty output + [[ -n $query_output ]] || exit_with_error "repoquery failed: package $package not found" + if grep --ignore-case --perl-regexp '\b(? +get_packages_with_version_arch() { + local result_var_name="$1" + shift + local packages=("$@") + local packages_with_version_arch=() + + for package in "${packages[@]}"; do + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + packages_with_version_arch+=("$QUERY_OUTPUT") + done + + eval $result_var_name='("${packages_with_version_arch[@]}")' +} + +# params: +get_requirements_from_group() { + # $1 reserved for result + local group_name="$2" + local requirements_file_path="$3" + + local all_requirements=$(grep --only-matching '^[^#]*' "$requirements_file_path" | sed -e 's/[[:space:]]*$//') + local requirements_from_group=$(awk "/^$/ {next}; /\[${group_name}\]/ {f=1; next}; /^\[/ {f=0}; f {print \$0}" <<< "$all_requirements") || + exit_with_error "Function get_requirements_from_group failed for group: $group_name" + + [[ -n $requirements_from_group ]] || echol "No requirements found for group: $group_name" + + eval $1='$requirements_from_group' +} + +# params: +get_unique_array() { + local result_var_name="$1" + shift + local array=("$@") + + # filter out duplicates + array=($(echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + + eval $result_var_name='("${array[@]}")' +} + +# params: [package_name] +install_package() { + local package_name_or_url="$1" + local package_name="$1" + + [ $# -gt 1 ] && package_name="$2" + + echol "Installing package: $package_name" + if yum install -y "$package_name_or_url"; then + echo "$package_name" >> "$INSTALLED_PACKAGES_FILE_PATH" + else + exit_with_error "Command failed: yum install -y \"$package_name_or_url\"" + fi +} + +# params: +is_package_installed() { + local package="$1" + + if rpm --query --quiet "$package"; then + echol "Package $package already installed" + return 0 + else + return 1 + fi +} + +# params: +is_repo_enabled() { + local repo_id="$1" + + if yum repolist | grep --quiet "$repo_id"; then + echol "Repository $repo_id already enabled" + return 0 + else + return 1 + fi +} + +# params: +remove_package() { + local package="$1" + + if rpm --query --quiet "$package"; then + echol "Removing package: $package" + yum remove -y "$package" || exit_with_error "Command failed: yum remove -y \"$package\"" + fi +} + +# params: +remove_added_repos() { + local added_repos_list_file="$1" + + if [ -f "$added_repos_list_file" ]; then + for repo_config_file in $(cat $added_repos_list_file | sort --unique); do + remove_file "/etc/yum.repos.d/$repo_config_file" + done + remove_file "$added_repos_list_file" + fi +} + +# params: +remove_file() { + local file_path="$1" + + echol "Removing file: $file_path" + rm -f "$file_path" || exit_with_error "Command failed: rm -f \"$file_path\"" +} + +# params: +remove_installed_packages() { + local installed_packages_list_file="$1" + + if [ -f "$installed_packages_list_file" ]; then + for package in $(cat $installed_packages_list_file | sort --unique); do + remove_package "$package" + done + remove_file "$installed_packages_list_file" + fi +} + +usage() { + echo "usage: ./$(basename $0) " + echo " ./$(basename $0) /tmp/downloads" + [ -z "$1" ] || exit "$1" +} + +# === Start === + +[ $# -gt 0 ] || usage 1 >&2 +readonly START_TIME=$(date +%s) + +# --- Parse arguments --- + +POSITIONAL_ARGS=() +CREATE_LOGFILE='yes' +while [[ $# -gt 0 ]]; do +case $1 in + --no-logfile) + CREATE_LOGFILE='no' + shift # past argument + ;; + *) # unknown option + POSITIONAL_ARGS+=("$1") # save it in an array for later + shift + ;; +esac +done +set -- "${POSITIONAL_ARGS[@]}" # restore positional arguments + +# --- Global variables --- + +# dirs +readonly DOWNLOADS_DIR="$1" # root directory for downloads +readonly FILES_DIR="$DOWNLOADS_DIR/files" +readonly PACKAGES_DIR="$DOWNLOADS_DIR/packages" +readonly IMAGES_DIR="$DOWNLOADS_DIR/images" +readonly REPO_PREREQ_PACKAGES_DIR="$PACKAGES_DIR/repo-prereqs" +readonly SCRIPT_DIR="$(dirname $(readlink -f $0))" # want absolute path + +# files +readonly REQUIREMENTS_FILE_PATH="$SCRIPT_DIR/requirements.txt" +readonly SCRIPT_FILE_NAME=$(basename $0) +readonly LOG_FILE_NAME=${SCRIPT_FILE_NAME/sh/log} +readonly LOG_FILE_PATH="$SCRIPT_DIR/$LOG_FILE_NAME" +readonly YUM_CONFIG_BACKUP_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-yum-repos-backup-tmp-do-not-remove.tar" +readonly SKOPEO_BIN="$SCRIPT_DIR/skopeo_linux" +readonly ADDED_REPOSITORIES_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-added-repositories-list-do-not-remove.tmp" +readonly INSTALLED_PACKAGES_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-installed-packages-list-do-not-remove.tmp" +readonly PID_FILE_PATH=/var/run/${SCRIPT_FILE_NAME/sh/pid} + +# --- Checks --- + +[ $EUID -eq 0 ] || { echo "You have to run as root" && exit 1; } + +[[ -f $REQUIREMENTS_FILE_PATH ]] || exit_with_error "File not found: $REQUIREMENTS_FILE_PATH" +[[ -f $SKOPEO_BIN ]] || exit_with_error "File not found: $SKOPEO_BIN" +[[ -x $SKOPEO_BIN ]] || exit_with_error "$SKOPEO_BIN have to be executable" + +# --- Want to have only one instance for Ansible --- + +if [ -f $PID_FILE_PATH ]; then + readonly PID_FROM_FILE=$(cat $PID_FILE_PATH 2> /dev/null) + if [[ -n $PID_FROM_FILE ]] && kill -0 $PID_FROM_FILE > /dev/null 2>&1; then + echol "Found running process with pid: $PID_FROM_FILE, cmd: $(ps -p $PID_FROM_FILE -o cmd=)" + if ps -p $PID_FROM_FILE -o cmd= | grep --quiet $SCRIPT_FILE_NAME; then + echol "Killing old instance using SIGTERM" + kill -s SIGTERM $PID_FROM_FILE # try gracefully + if sleep 3 && kill -0 $PID_FROM_FILE > /dev/null 2>&1; then + echol "Still running, killing old instance using SIGKILL" + kill -s SIGKILL $PID_FROM_FILE # forcefully + fi + else + remove_file $PID_FILE_PATH + exit_with_error "Process with pid: $PID_FILE_PATH seems to be not an instance of this script" + fi + else + echol "Process with pid: $PID_FROM_FILE not found" + fi + remove_file $PID_FILE_PATH +fi + +echol "PID is: $$, creating file: $PID_FILE_PATH" +echo $$ > $PID_FILE_PATH || exit_with_error "Command failed: echo $$ > $PID_FILE_PATH" + +# --- Parse requirements file --- + +# Requirements are grouped using sections: [packages-repo-prereqs], [packages], [files], [images] +get_requirements_from_group 'REPO_PREREQ_PACKAGES' 'packages-repo-prereqs' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'PACKAGES' 'packages' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'FILES' 'files' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'IMAGES' 'images' "$REQUIREMENTS_FILE_PATH" + +# === Packages === + +# --- Backup yum repositories --- + +if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + echol "Backup aleady exists: $YUM_CONFIG_BACKUP_FILE_PATH" +else + echol "Backuping /etc/yum.repos.d/ to $YUM_CONFIG_BACKUP_FILE_PATH" + if backup_files $YUM_CONFIG_BACKUP_FILE_PATH '/etc/yum.repos.d/'; then + echol "Backup done" + else + if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + remove_file $YUM_CONFIG_BACKUP_FILE_PATH + fi + exit_with_error "Backup of yum repositories failed" + fi +fi + +# --- Install required packages unless present --- + +# repos can be enabled or disabled using the yum-config-manager command, which is provided by yum-utils package +for package in 'yum-utils' 'wget'; do + if ! is_package_installed "$package"; then + install_package "$package" + fi +done + +# --- Enable OS repos --- + +# -> CentOS-7 - Extras # for container-selinux and centos-release-scl packages +enable_repo 'extras' + +# --- Add repos --- + +ELASTIC_REPO_CONF=$(cat <<'EOF' +[elastic-6] +name=Elastic repository for 6.x packages +baseurl=https://artifacts.elastic.co/packages/oss-6.x/yum +gpgcheck=1 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md +EOF +) + +ELASTICSEARCH_CURATOR_REPO_CONF=$(cat <<'EOF' +[curator-5] +name=CentOS/RHEL 7 repository for Elasticsearch Curator 5.x packages +baseurl=https://packages.elastic.co/curator/5/centos/7 +gpgcheck=1 +gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch +enabled=1 +EOF +) + +GRAFANA_REPO_CONF=$(cat <<'EOF' +[grafana] +name=grafana +baseurl=https://packages.grafana.com/oss/rpm +repo_gpgcheck=1 +enabled=1 +gpgcheck=1 +gpgkey=https://packages.grafana.com/gpg.key +sslverify=1 +sslcacert=/etc/pki/tls/certs/ca-bundle.crt +EOF +) + +KUBERNETES_REPO_CONF=$(cat <<'EOF' +[kubernetes] +name=Kubernetes +baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 +enabled=1 +gpgcheck=1 +repo_gpgcheck=1 +gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg +EOF +) + +RABBITMQ_ERLANG_REPO_CONF=$(cat <<'EOF' +[rabbitmq_erlang] +name=rabbitmq_erlang +baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/$basearch +repo_gpgcheck=1 +gpgcheck=1 +enabled=1 +gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey +EOF +) + +RABBITMQ_SERVER_REPO_CONF=$(cat <<'EOF' +[rabbitmq_rabbitmq-server] +name=rabbitmq_rabbitmq-server +baseurl=https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/$basearch +repo_gpgcheck=1 +gpgcheck=1 +enabled=1 +gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey +EOF +) + +add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' +add_repo_as_file 'elastic-6' "$ELASTIC_REPO_CONF" +add_repo_as_file 'curator-5' "$ELASTICSEARCH_CURATOR_REPO_CONF" +add_repo_as_file 'grafana' "$GRAFANA_REPO_CONF" +add_repo_as_file 'kubernetes' "$KUBERNETES_REPO_CONF" +add_repo_as_file 'rabbitmq_erlang' "$RABBITMQ_ERLANG_REPO_CONF" +add_repo_as_file 'rabbitmq_rabbitmq-server' "$RABBITMQ_SERVER_REPO_CONF" + +# -> Software Collections (SCL) https://wiki.centos.org/AdditionalResources/Repositories/SCL +if ! is_package_installed 'centos-release-scl'; then + # from extras repo + install_package 'centos-release-scl-rh' + install_package 'centos-release-scl' +fi + +# some packages are from EPEL repo +if ! is_package_installed 'epel-release'; then + install_package 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm' 'epel-release' +fi + +echol "Executing: yum -y makecache fast" && yum -y makecache fast + +# --- Download packages --- + +# 1) packages required to create repository + +create_directory "$REPO_PREREQ_PACKAGES_DIR" + +# prepare lists +PREREQ_PACKAGES=() +for package in $REPO_PREREQ_PACKAGES; do + echol "Processing package: $package" + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + PREREQ_PACKAGES+=("$QUERY_OUTPUT") +done + +# download requirements (fixed versions) +if [[ ${#PREREQ_PACKAGES[@]} -gt 0 ]]; then + echol "Downloading repository prerequisite packages (${#PREREQ_PACKAGES[@]})..." + download_packages "$REPO_PREREQ_PACKAGES_DIR" "${PREREQ_PACKAGES[@]}" +fi + +# 2) non-prerequisite packages + +create_directory "$PACKAGES_DIR" + +# prepare lists +NON_PREREQ_PACKAGES=() +DEPENDENCIES_OF_NON_PREREQ_PACKAGES=() +for package in $PACKAGES; do + echol "Processing package: $package" + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + NON_PREREQ_PACKAGES+=("$QUERY_OUTPUT") + get_package_dependencies_with_arch 'DEPENDENCIES' "$package" + if [[ ${#DEPENDENCIES[@]} -gt 0 ]]; then + for dependency in "${DEPENDENCIES[@]}"; do + DEPENDENCIES_OF_NON_PREREQ_PACKAGES+=("$dependency") + done + fi +done + +if [[ ${#NON_PREREQ_PACKAGES[@]} -gt 0 ]]; then + # download requirements (fixed versions) + echol "Downloading packages (${#NON_PREREQ_PACKAGES[@]})..." + download_packages "$PACKAGES_DIR" "${NON_PREREQ_PACKAGES[@]}" + # download dependencies (latest versions) + get_unique_array 'DEPENDENCIES' "${DEPENDENCIES_OF_NON_PREREQ_PACKAGES[@]}" + get_packages_with_version_arch 'DEPENDENCIES' "${DEPENDENCIES[@]}" + echol "Downloading dependencies of packages (${#DEPENDENCIES[@]})..." + download_packages "$PACKAGES_DIR" "${DEPENDENCIES[@]}" +fi + +# --- Clean up yum repos --- + +remove_added_repos "$ADDED_REPOSITORIES_FILE_PATH" + +# --- Restore yum repos --- + +if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + echol "Restoring /etc/yum.repos.d/*.repo from: $YUM_CONFIG_BACKUP_FILE_PATH" + echol "Executing: tar --extract --verbose --file $YUM_CONFIG_BACKUP_FILE_PATH" + if tar --extract --verbose --file $YUM_CONFIG_BACKUP_FILE_PATH --directory /etc/yum.repos.d \ + --strip-components=2 etc/yum.repos.d/*.repo; then + echol "Restored: yum repositories" + remove_file $YUM_CONFIG_BACKUP_FILE_PATH + else + exit_with_error "Extracting tar failed: $YUM_CONFIG_BACKUP_FILE_PATH" + fi +fi + +# === Files === + +create_directory "$FILES_DIR" + +for file in $FILES; do + download_file "$file" "$FILES_DIR" +done + +# === Images === + +create_directory "$IMAGES_DIR" + +for image in $IMAGES; do + download_image "$image" "$IMAGES_DIR" +done + +# --- Clean up packages --- +remove_installed_packages "$INSTALLED_PACKAGES_FILE_PATH" + +remove_file $PID_FILE_PATH + +readonly END_TIME=$(date +%s) + +echol "$(basename $0) finished, execution time: $(date -u -d @$((END_TIME-START_TIME)) +'%Hh:%Mm:%Ss')" \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/requirements.txt b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/requirements.txt new file mode 100644 index 0000000000..531d1214ec --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/requirements.txt @@ -0,0 +1,138 @@ +# Put this file in the same directory as download script + +[packages-repo-prereqs] +apr # for httpd +apr-util # for httpd +createrepo +deltarpm # for createrepo +httpd +httpd-tools # for httpd +libxml2-python # for createrepo +mailcap # for httpd +mod_ssl # for httpd +python-chardet # for createrepo +python-deltarpm # for createrepo +python-kitchen # for createrepo +yum-utils + + +[packages] +audit # for docker-ce +bash-completion +ca-certificates +cifs-utils +conntrack-tools # for kubelet +containerd.io +container-selinux +cri-tools-1.13.0 +curl +dejavu-sans-fonts # for grafana +docker-ce-18.09.9 +docker-ce-cli-18.09.9 +ebtables +elasticsearch-curator-5.5.4 +elasticsearch-oss-6.4.0 +erlang-21.3.8.7 +ethtool +filebeat-6.5.4 # actually it's filebeat-oss +firewalld +fontconfig # for grafana +fping +grafana-6.2.5 +gssproxy # for nfs-utils +htop +iftop +ipset # for firewalld +java-1.8.0-openjdk-headless +javapackages-tools # for java-1.8.0-openjdk-headless +jq +kibana-oss-6.4.0 +kubeadm-1.14.6 +kubectl-1.14.6 +kubelet-1.14.6 +kubernetes-cni-0.7.5 +libini_config # for nfs-utils +libselinux-python +libsemanage-python +libX11 # for grafana +libxcb # for grafana +libXcursor # for grafana +libXt # for grafana +logrotate +net-tools +nfs-utils +nmap-ncat +openssl +perl # for vim +perl-Getopt-Long # for vim +perl-libs # for vim +perl-Pod-Perldoc # for vim +perl-Pod-Simple # for vim +perl-Pod-Usage # for vim +policycoreutils-python # for container-selinux +python-firewall # for firewalld +python-kitchen # for yum-utils +python-lxml # for java-1.8.0-openjdk-headless +python-psycopg2 +python-setuptools +python-slip-dbus # for firewalld +python-ipaddress +python-backports +quota # for nfs-utils +rabbitmq-server-3.7.10 +rh-haproxy18 +rh-haproxy18-haproxy-syspaths +rh-postgresql10-postgresql +rh-postgresql10-postgresql-contrib +rh-postgresql10-postgresql-contrib-syspaths +rh-postgresql10-postgresql-libs +rh-postgresql10-postgresql-server +rh-postgresql10-postgresql-server-syspaths +rh-postgresql10-postgresql-syspaths +samba-client +samba-client-libs # for samba-client +samba-common +socat +sysstat +tar +telnet +tmux +urw-base35-fonts # for grafana +vim-common # for vim +vim-enhanced +wget +xorg-x11-font-utils # for grafana +xorg-x11-server-utils # for grafana +yum-plugin-versionlock +yum-utils + +[files] +https://github.com/prometheus/haproxy_exporter/releases/download/v0.10.0/haproxy_exporter-0.10.0.linux-amd64.tar.gz +https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.12.0/jmx_prometheus_javaagent-0.12.0.jar +https://archive.apache.org/dist/kafka/2.0.0/kafka_2.12-2.0.0.tgz +https://github.com/danielqsj/kafka_exporter/releases/download/v1.2.0/kafka_exporter-1.2.0.linux-amd64.tar.gz +https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz +https://github.com/prometheus/prometheus/releases/download/v2.10.0/prometheus-2.10.0.linux-amd64.tar.gz +https://github.com/prometheus/alertmanager/releases/download/v0.17.0/alertmanager-0.17.0.linux-amd64.tar.gz +https://archive.apache.org/dist/zookeeper/zookeeper-3.4.12/zookeeper-3.4.12.tar.gz + +[images] +k8s.gcr.io/kube-apiserver:v1.14.6 +k8s.gcr.io/kube-controller-manager:v1.14.6 +k8s.gcr.io/kube-scheduler:v1.14.6 +k8s.gcr.io/kube-proxy:v1.14.6 +k8s.gcr.io/pause:3.1 +k8s.gcr.io/etcd:3.3.10 +k8s.gcr.io/coredns:1.3.1 +coredns/coredns:1.5.0 +quay.io/coreos/flannel:v0.11.0-amd64 +quay.io/coreos/flannel:v0.11.0 +calico/node:v3.8.1 +calico/pod2daemon-flexvol:v3.8.1 +kubernetesui/dashboard:v2.0.0-beta1 +kubernetesui/metrics-scraper:v1.0.0 +calico/cni:v3.8.1 +calico/kube-controllers:v3.8.1 +jboss/keycloak:4.8.3.Final +rabbitmq:3.7.10 +registry:2 \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh new file mode 100644 index 0000000000..dbcbff0094 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh @@ -0,0 +1,634 @@ +#!/usr/bin/env bash + +# VERSION 1.0.3 + +# NOTE: You can run only one instance of this script, new instance kills the previous one +# This limitation is for Ansible + +set -euo pipefail + +# === Functions (in alphabetical order) === + +# params: +add_repo() { + local repo_id="$1" + local repo_url="$2" + + if ! is_repo_enabled "$repo_id"; then + echol "Adding repository: $repo_id" + yum-config-manager --add-repo "$repo_url" || + exit_with_error "Command failed: yum-config-manager --add-repo \"$repo_url\"" + echo "$repo_id.repo" >> "$ADDED_REPOSITORIES_FILE_PATH" + # to accept import of GPG keys + yum -y repolist > /dev/null || + exit_with_error "Command failed: yum -y repolist" + fi +} + +# params: +add_repo_as_file() { + local repo_id="$1" + local config_file_contents="$2" + local config_file_name="$repo_id.repo" + + if ! is_repo_enabled "$repo_id"; then + echol "Adding repository: $repo_id" + cat <<< "$config_file_contents" > "/etc/yum.repos.d/$config_file_name" || + exit_with_error "Function add_repo_as_file failed for repo: $repo_id" + echo "$config_file_name" >> "$ADDED_REPOSITORIES_FILE_PATH" + # to accept import of GPG keys + yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" + fi +} + +# params: ... [path_N_to_backup] +backup_files() { + local backup_file_path="$1" + shift + local paths_to_backup="$@" + + # --directory='/' is for tar --verify + tar --create --verbose --verify --directory="/" --file="$backup_file_path" $paths_to_backup +} + +# params: +create_directory() { + local dir_path="$1" + + if [[ -d "$dir_path" ]]; then + echol "Directory $dir_path already exists" + else + echol "Creating directory: $dir_path" + mkdir -p "$dir_path" || exit_with_error "Command failed: mkdir -p \"$dir_path\"" + fi +} + +# params: +download_file() { + local file_url="$1" + local dest_dir="$2" + + local file_name=$(basename "$file_url") + local dest_path="$dest_dir/$file_name" + + # wget with --timestamping sometimes failes on AWS with ERROR 403: Forbidden + # so we remove existing file to overwrite it, to be optimized + [[ ! -f $dest_path ]] || remove_file "$dest_path" + + echol "Downloading file: $file" + + wget --no-verbose --directory-prefix="$dest_dir" "$file_url" || + exit_with_error "Command failed: wget --no-verbose --directory-prefix=\"$dest_dir\" \"$file_url\"" +} + +# params: +download_image() { + local image_name="$1" + local dest_dir="$2" + + local splited_image=(${image_name//:/ }) + local repository=${splited_image[0]} + local tag=${splited_image[1]} + local repo_basename=$(basename -- "$repository") + local dest_path="${dest_dir}/${repo_basename}-${tag}.tar" + + if [[ -f $dest_path ]]; then + echol "Image file: "$dest_path" already exists. Skipping..." + else + # use temporary file for downloading to be safe from sudden interruptions (network, ctrl+c) + local tmp_file_path=$(mktemp) + local skopeo_cmd="$SKOPEO_BIN --insecure-policy copy docker://$image_name docker-archive:$tmp_file_path:$repository:$tag" + echol "Downloading image: $image" + { $skopeo_cmd && chmod 644 $tmp_file_path && mv $tmp_file_path $dest_path; } || + exit_with_error "skopeo failed, command was: $skopeo_cmd && chmod 644 $tmp_file_path && mv $tmp_file_path $dest_path" + fi +} + +# params: ... [package_N] +download_packages() { + local dest_dir="$1" + shift + local packages="$@" + + if [[ -n $packages ]]; then + # when using --archlist=x86_64 yumdownloader (yum-utils-1.1.31-52) also downloads i686 packages + yumdownloader --quiet --archlist=x86_64 --exclude='*i686' --destdir="$dest_dir" $packages || + exit_with_error "yumdownloader failed for: $packages" + fi +} + +echol() { + echo -e "$@" + if [[ $CREATE_LOGFILE == 'yes' ]]; then + local timestamp=$(date +"%b %e %H:%M:%S") + echo -e "${timestamp}: $@" >> "$LOG_FILE_PATH" + fi +} + +# params: +enable_repo() { + local repo_id="$1" + + if ! yum repolist enabled | grep --quiet "$repo_id"; then + echol "Enabling repository: $repo_id" + yum-config-manager --enable "$repo_id" || + exit_with_error "Command failed: yum-config-manager --enable \"$repo_id\"" + fi +} + +exit_with_error() { + echol "ERROR: $1" + exit 1 +} + +# desc: find repo id (set $1) based on given pattern +# params: +find_rhel_repo_id() { + # $1 reserved for result + local rhel_on_prem_repo_id="$2" + local pattern="$3" + local repo_id + + if yum repolist all | egrep --quiet "$pattern"; then + repo_id=$(yum repolist all | egrep --only-matching "$pattern") + else + exit_with_error "RHEL yum repository not found, pattern was: $pattern" + fi + + eval $1='$repo_id' +} + +# params: +get_package_dependencies_with_arch() { + # $1 reserved for result + local package="$2" + + local query_output=$(repoquery --requires --resolve --queryformat '%{name}.%{arch}' --archlist=x86_64,noarch "$package") || + exit_with_error "repoquery failed for dependencies of package: $package with exit code: $?, output was: $query_output" + + if [[ -z $query_output ]]; then + echol "No dependencies found for package: $package" + elif grep --ignore-case --perl-regexp '\b(? +get_package_with_version_arch() { + # $1 reserved for result + local package="$2" + + local query_output=$(repoquery --queryformat '%{ui_nevra}' --archlist=x86_64,noarch "$package") || + exit_with_error "repoquery failed for package: $package with exit code: $?, output was: $query_output" + + # yumdownloader doesn't set error code if repoquery returns empty output + [[ -n $query_output ]] || exit_with_error "repoquery failed: package $package not found" + if grep --ignore-case --perl-regexp '\b(? +get_packages_with_version_arch() { + local result_var_name="$1" + shift + local packages=("$@") + local packages_with_version_arch=() + + for package in "${packages[@]}"; do + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + packages_with_version_arch+=("$QUERY_OUTPUT") + done + + eval $result_var_name='("${packages_with_version_arch[@]}")' +} + +# params: +get_requirements_from_group() { + # $1 reserved for result + local group_name="$2" + local requirements_file_path="$3" + + local all_requirements=$(grep --only-matching '^[^#]*' "$requirements_file_path" | sed -e 's/[[:space:]]*$//') + local requirements_from_group=$(awk "/^$/ {next}; /\[${group_name}\]/ {f=1; next}; /^\[/ {f=0}; f {print \$0}" <<< "$all_requirements") || + exit_with_error "Function get_requirements_from_group failed for group: $group_name" + + [[ -n $requirements_from_group ]] || echol "No requirements found for group: $group_name" + + eval $1='$requirements_from_group' +} + +# params: +get_unique_array() { + local result_var_name="$1" + shift + local array=("$@") + + # filter out duplicates + array=($(echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + + eval $result_var_name='("${array[@]}")' +} + +# params: [package_name] +install_package() { + local package_name_or_url="$1" + local package_name="$1" + + [ $# -gt 1 ] && package_name="$2" + + echol "Installing package: $package_name" + if yum install -y "$package_name_or_url"; then + echo "$package_name" >> "$INSTALLED_PACKAGES_FILE_PATH" + else + exit_with_error "Command failed: yum install -y \"$package_name_or_url\"" + fi +} + +# params: +is_package_installed() { + local package="$1" + + if rpm --query --quiet "$package"; then + echol "Package $package already installed" + return 0 + else + return 1 + fi +} + +# params: +is_repo_enabled() { + local repo_id="$1" + + if yum repolist | grep --quiet "$repo_id"; then + echol "Repository $repo_id already enabled" + return 0 + else + return 1 + fi +} + +# params: +remove_package() { + local package="$1" + + if rpm --query --quiet "$package"; then + echol "Removing package: $package" + yum remove -y "$package" || exit_with_error "Command failed: yum remove -y \"$package\"" + fi +} + +# params: +remove_added_repos() { + local added_repos_list_file="$1" + + if [ -f "$added_repos_list_file" ]; then + for repo_config_file in $(cat $added_repos_list_file | sort --unique); do + remove_file "/etc/yum.repos.d/$repo_config_file" + done + remove_file "$added_repos_list_file" + fi +} + +# params: +remove_file() { + local file_path="$1" + + echol "Removing file: $file_path" + rm -f "$file_path" || exit_with_error "Command failed: rm -f \"$file_path\"" +} + +# params: +remove_installed_packages() { + local installed_packages_list_file="$1" + + if [ -f "$installed_packages_list_file" ]; then + for package in $(cat $installed_packages_list_file | sort --unique); do + remove_package "$package" + done + remove_file "$installed_packages_list_file" + fi +} + +usage() { + echo "usage: ./$(basename $0) " + echo " ./$(basename $0) /tmp/downloads" + [ -z "$1" ] || exit "$1" +} + +# === Start === + +[ $# -gt 0 ] || usage 1 >&2 +readonly START_TIME=$(date +%s) + +# --- Parse arguments --- + +POSITIONAL_ARGS=() +CREATE_LOGFILE='yes' +while [[ $# -gt 0 ]]; do +case $1 in + --no-logfile) + CREATE_LOGFILE='no' + shift # past argument + ;; + *) # unknown option + POSITIONAL_ARGS+=("$1") # save it in an array for later + shift + ;; +esac +done +set -- "${POSITIONAL_ARGS[@]}" # restore positional arguments + +# --- Global variables --- + +# dirs +readonly DOWNLOADS_DIR="$1" # root directory for downloads +readonly FILES_DIR="$DOWNLOADS_DIR/files" +readonly PACKAGES_DIR="$DOWNLOADS_DIR/packages" +readonly IMAGES_DIR="$DOWNLOADS_DIR/images" +readonly REPO_PREREQ_PACKAGES_DIR="$PACKAGES_DIR/repo-prereqs" +readonly SCRIPT_DIR="$(dirname $(readlink -f $0))" # want absolute path + +# files +readonly REQUIREMENTS_FILE_PATH="$SCRIPT_DIR/requirements.txt" +readonly SCRIPT_FILE_NAME=$(basename $0) +readonly LOG_FILE_NAME=${SCRIPT_FILE_NAME/sh/log} +readonly LOG_FILE_PATH="$SCRIPT_DIR/$LOG_FILE_NAME" +readonly YUM_CONFIG_BACKUP_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-yum-repos-backup-tmp-do-not-remove.tar" +readonly SKOPEO_BIN="$SCRIPT_DIR/skopeo_linux" +readonly ADDED_REPOSITORIES_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-added-repositories-list-do-not-remove.tmp" +readonly INSTALLED_PACKAGES_FILE_PATH="$SCRIPT_DIR/${SCRIPT_FILE_NAME}-installed-packages-list-do-not-remove.tmp" +readonly PID_FILE_PATH=/var/run/${SCRIPT_FILE_NAME/sh/pid} + +# --- Checks --- + +[ $EUID -eq 0 ] || { echo "You have to run as root" && exit 1; } + +[[ -f $REQUIREMENTS_FILE_PATH ]] || exit_with_error "File not found: $REQUIREMENTS_FILE_PATH" +[[ -f $SKOPEO_BIN ]] || exit_with_error "File not found: $SKOPEO_BIN" +[[ -x $SKOPEO_BIN ]] || exit_with_error "$SKOPEO_BIN have to be executable" + +# --- Want to have only one instance for Ansible --- + +if [ -f $PID_FILE_PATH ]; then + readonly PID_FROM_FILE=$(cat $PID_FILE_PATH 2> /dev/null) + if [[ -n $PID_FROM_FILE ]] && kill -0 $PID_FROM_FILE > /dev/null 2>&1; then + echol "Found running process with pid: $PID_FROM_FILE, cmd: $(ps -p $PID_FROM_FILE -o cmd=)" + if ps -p $PID_FROM_FILE -o cmd= | grep --quiet $SCRIPT_FILE_NAME; then + echol "Killing old instance using SIGTERM" + kill -s SIGTERM $PID_FROM_FILE # try gracefully + if sleep 3 && kill -0 $PID_FROM_FILE > /dev/null 2>&1; then + echol "Still running, killing old instance using SIGKILL" + kill -s SIGKILL $PID_FROM_FILE # forcefully + fi + else + remove_file $PID_FILE_PATH + exit_with_error "Process with pid: $PID_FILE_PATH seems to be not an instance of this script" + fi + else + echol "Process with pid: $PID_FROM_FILE not found" + fi + remove_file $PID_FILE_PATH +fi + +echol "PID is: $$, creating file: $PID_FILE_PATH" +echo $$ > $PID_FILE_PATH || exit_with_error "Command failed: echo $$ > $PID_FILE_PATH" + +# --- Parse requirements file --- + +# Requirements are grouped using sections: [packages-repo-prereqs], [packages], [files], [images] +get_requirements_from_group 'REPO_PREREQ_PACKAGES' 'packages-repo-prereqs' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'PACKAGES' 'packages' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'FILES' 'files' "$REQUIREMENTS_FILE_PATH" +get_requirements_from_group 'IMAGES' 'images' "$REQUIREMENTS_FILE_PATH" + +# === Packages === + +# --- Backup yum repositories --- + +if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + echol "Backup aleady exists: $YUM_CONFIG_BACKUP_FILE_PATH" +else + echol "Backuping /etc/yum.repos.d/ to $YUM_CONFIG_BACKUP_FILE_PATH" + if backup_files $YUM_CONFIG_BACKUP_FILE_PATH '/etc/yum.repos.d/'; then + echol "Backup done" + else + if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + remove_file $YUM_CONFIG_BACKUP_FILE_PATH + fi + exit_with_error "Backup of yum repositories failed" + fi +fi + +# --- Install required packages unless present --- + +# repos can be enabled or disabled using the yum-config-manager command, which is provided by yum-utils package +for package in 'yum-utils' 'wget'; do + if ! is_package_installed "$package"; then + install_package "$package" + fi +done + +# --- Enable RHEL repos --- + +# -> rhel-7-server-extras-rpms # for container-selinux package, this repo has different id names on clouds +# About rhel-7-server-extras-rpms: https://access.redhat.com/solutions/3418891 + +ON_PREM_REPO_ID='rhel-7-server-extras-rpms' +REPO_ID_PATTERN="$ON_PREM_REPO_ID|rhui-REGION-rhel-server-extras|rhui-rhel-7-server-rhui-extras-rpms" # on-prem|AWS|Azure +find_rhel_repo_id 'REPO_ID' "$ON_PREM_REPO_ID" "$REPO_ID_PATTERN" +enable_repo "$REPO_ID" + +# -> rhel-server-rhscl-7-rpms # for Red Hat Software Collections (RHSCL), this repo has different id names on clouds +# About rhel-server-rhscl-7-rpms: https://access.redhat.com/solutions/472793 + +ON_PREM_REPO_ID='rhel-server-rhscl-7-rpms' +REPO_ID_PATTERN="$ON_PREM_REPO_ID|rhui-REGION-rhel-server-rhscl|rhui-rhel-server-rhui-rhscl-7-rpms" # on-prem|AWS|Azure +find_rhel_repo_id 'REPO_ID' "$ON_PREM_REPO_ID" "$REPO_ID_PATTERN" +enable_repo "$REPO_ID" + +# --- Add repos --- + +ELASTIC_REPO_CONF=$(cat <<'EOF' +[elastic-6] +name=Elastic repository for 6.x packages +baseurl=https://artifacts.elastic.co/packages/oss-6.x/yum +gpgcheck=1 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md +EOF +) + +ELASTICSEARCH_CURATOR_REPO_CONF=$(cat <<'EOF' +[curator-5] +name=CentOS/RHEL 7 repository for Elasticsearch Curator 5.x packages +baseurl=https://packages.elastic.co/curator/5/centos/7 +gpgcheck=1 +gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch +enabled=1 +EOF +) + +GRAFANA_REPO_CONF=$(cat <<'EOF' +[grafana] +name=grafana +baseurl=https://packages.grafana.com/oss/rpm +repo_gpgcheck=1 +enabled=1 +gpgcheck=1 +gpgkey=https://packages.grafana.com/gpg.key +sslverify=1 +sslcacert=/etc/pki/tls/certs/ca-bundle.crt +EOF +) + +KUBERNETES_REPO_CONF=$(cat <<'EOF' +[kubernetes] +name=Kubernetes +baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 +enabled=1 +gpgcheck=1 +repo_gpgcheck=1 +gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg +EOF +) + +RABBITMQ_ERLANG_REPO_CONF=$(cat <<'EOF' +[rabbitmq_erlang] +name=rabbitmq_erlang +baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/$basearch +repo_gpgcheck=1 +gpgcheck=1 +enabled=1 +gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey +EOF +) + +RABBITMQ_SERVER_REPO_CONF=$(cat <<'EOF' +[rabbitmq_rabbitmq-server] +name=rabbitmq_rabbitmq-server +baseurl=https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/$basearch +repo_gpgcheck=1 +gpgcheck=1 +enabled=1 +gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey +EOF +) + +add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' +add_repo_as_file 'elastic-6' "$ELASTIC_REPO_CONF" +add_repo_as_file 'curator-5' "$ELASTICSEARCH_CURATOR_REPO_CONF" +add_repo_as_file 'grafana' "$GRAFANA_REPO_CONF" +add_repo_as_file 'kubernetes' "$KUBERNETES_REPO_CONF" +add_repo_as_file 'rabbitmq_erlang' "$RABBITMQ_ERLANG_REPO_CONF" +add_repo_as_file 'rabbitmq_rabbitmq-server' "$RABBITMQ_SERVER_REPO_CONF" + +# some packages are from EPEL repo +if ! is_package_installed 'epel-release'; then + install_package 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm' 'epel-release' +fi + +echol "Executing: yum -y makecache fast" && yum -y makecache fast + +# --- Download packages --- + +# 1) packages required to create repository + +create_directory "$REPO_PREREQ_PACKAGES_DIR" + +# prepare lists +PREREQ_PACKAGES=() +for package in $REPO_PREREQ_PACKAGES; do + echol "Processing package: $package" + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + PREREQ_PACKAGES+=("$QUERY_OUTPUT") +done + +# download requirements (fixed versions) +if [[ ${#PREREQ_PACKAGES[@]} -gt 0 ]]; then + echol "Downloading repository prerequisite packages (${#PREREQ_PACKAGES[@]})..." + download_packages "$REPO_PREREQ_PACKAGES_DIR" "${PREREQ_PACKAGES[@]}" +fi + +# 2) non-prerequisite packages + +create_directory "$PACKAGES_DIR" + +# prepare lists +NON_PREREQ_PACKAGES=() +DEPENDENCIES_OF_NON_PREREQ_PACKAGES=() +for package in $PACKAGES; do + echol "Processing package: $package" + get_package_with_version_arch 'QUERY_OUTPUT' "$package" + NON_PREREQ_PACKAGES+=("$QUERY_OUTPUT") + get_package_dependencies_with_arch 'DEPENDENCIES' "$package" + if [[ ${#DEPENDENCIES[@]} -gt 0 ]]; then + for dependency in "${DEPENDENCIES[@]}"; do + DEPENDENCIES_OF_NON_PREREQ_PACKAGES+=("$dependency") + done + fi +done + +if [[ ${#NON_PREREQ_PACKAGES[@]} -gt 0 ]]; then + # download requirements (fixed versions) + echol "Downloading packages (${#NON_PREREQ_PACKAGES[@]})..." + download_packages "$PACKAGES_DIR" "${NON_PREREQ_PACKAGES[@]}" + # download dependencies (latest versions) + get_unique_array 'DEPENDENCIES' "${DEPENDENCIES_OF_NON_PREREQ_PACKAGES[@]}" + get_packages_with_version_arch 'DEPENDENCIES' "${DEPENDENCIES[@]}" + echol "Downloading dependencies of packages (${#DEPENDENCIES[@]})..." + download_packages "$PACKAGES_DIR" "${DEPENDENCIES[@]}" +fi + +# --- Clean up yum repos --- + +remove_added_repos "$ADDED_REPOSITORIES_FILE_PATH" + +# --- Restore yum repos --- + +if [ -f $YUM_CONFIG_BACKUP_FILE_PATH ]; then + echol "Restoring /etc/yum.repos.d/*.repo from: $YUM_CONFIG_BACKUP_FILE_PATH" + echol "Executing: tar --extract --verbose --file $YUM_CONFIG_BACKUP_FILE_PATH" + if tar --extract --verbose --file $YUM_CONFIG_BACKUP_FILE_PATH --directory /etc/yum.repos.d \ + --strip-components=2 etc/yum.repos.d/*.repo; then + echol "Restored: yum repositories" + remove_file $YUM_CONFIG_BACKUP_FILE_PATH + else + exit_with_error "Extracting tar failed: $YUM_CONFIG_BACKUP_FILE_PATH" + fi +fi + +# === Files === + +create_directory "$FILES_DIR" + +for file in $FILES; do + download_file "$file" "$FILES_DIR" +done + +# === Images === + +create_directory "$IMAGES_DIR" + +for image in $IMAGES; do + download_image "$image" "$IMAGES_DIR" +done + +# --- Clean up packages --- +remove_installed_packages "$INSTALLED_PACKAGES_FILE_PATH" + +remove_file $PID_FILE_PATH + +readonly END_TIME=$(date +%s) + +echol "$(basename $0) finished, execution time: $(date -u -d @$((END_TIME-START_TIME)) +'%Hh:%Mm:%Ss')" \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/requirements.txt b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/requirements.txt new file mode 100644 index 0000000000..38dcd0e47d --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/requirements.txt @@ -0,0 +1,134 @@ +# Put this file in the same directory as download script + +[packages-repo-prereqs] +apr # for httpd +apr-util # for httpd +createrepo +deltarpm # for createrepo +httpd +httpd-tools # for httpd +mailcap # for httpd +mod_ssl # for httpd +python-chardet # for createrepo +python-deltarpm # for createrepo +python-kitchen # for createrepo +yum-utils + +[packages] +audit # for docker-ce +bash-completion +ca-certificates +cifs-utils +conntrack-tools # for kubelet +containerd.io +container-selinux +cri-tools-1.13.0 +curl +dejavu-sans-fonts # for grafana +docker-ce-18.09.9 +docker-ce-cli-18.09.9 +ebtables +elasticsearch-curator-5.5.4 +elasticsearch-oss-6.4.0 +erlang-21.3.8.7 +ethtool +filebeat-6.5.4 # actually it's filebeat-oss +firewalld +fontconfig # for grafana +fping +grafana-6.2.5 +gssproxy # for nfs-utils +htop +iftop +ipset # for firewalld +java-1.8.0-openjdk-headless +javapackages-tools # for java-1.8.0-openjdk-headless +jq +kibana-oss-6.4.0 +kubeadm-1.14.6 +kubectl-1.14.6 +kubelet-1.14.6 +kubernetes-cni-0.7.5 +libini_config # for nfs-utils +libselinux-python +libsemanage-python +libX11 # for grafana +libxcb # for grafana +libXcursor # for grafana +libXt # for grafana +logrotate +net-tools +nfs-utils +nmap-ncat +openssl +perl # for vim +perl-Getopt-Long # for vim +perl-libs # for vim +perl-Pod-Perldoc # for vim +perl-Pod-Simple # for vim +perl-Pod-Usage # for vim +policycoreutils-python # for container-selinux +python-firewall # for firewalld +python-kitchen # for yum-utils +python-lxml # for java-1.8.0-openjdk-headless +python-psycopg2 +python-setuptools +python-slip-dbus # for firewalld +quota # for nfs-utils +rabbitmq-server-3.7.10 +rh-haproxy18 +rh-haproxy18-haproxy-syspaths +rh-postgresql10-postgresql +rh-postgresql10-postgresql-contrib +rh-postgresql10-postgresql-contrib-syspaths +rh-postgresql10-postgresql-libs +rh-postgresql10-postgresql-server +rh-postgresql10-postgresql-server-syspaths +rh-postgresql10-postgresql-syspaths +samba-client +samba-client-libs # for samba-client +samba-common +socat +sysstat +tar +telnet +tmux +urw-base35-fonts # for grafana +vim-common # for vim +vim-enhanced +wget +xorg-x11-font-utils # for grafana +xorg-x11-server-utils # for grafana +yum-plugin-versionlock +yum-utils + +[files] +https://github.com/prometheus/haproxy_exporter/releases/download/v0.10.0/haproxy_exporter-0.10.0.linux-amd64.tar.gz +https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.12.0/jmx_prometheus_javaagent-0.12.0.jar +https://archive.apache.org/dist/kafka/2.0.0/kafka_2.12-2.0.0.tgz +https://github.com/danielqsj/kafka_exporter/releases/download/v1.2.0/kafka_exporter-1.2.0.linux-amd64.tar.gz +https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz +https://github.com/prometheus/prometheus/releases/download/v2.10.0/prometheus-2.10.0.linux-amd64.tar.gz +https://github.com/prometheus/alertmanager/releases/download/v0.17.0/alertmanager-0.17.0.linux-amd64.tar.gz +https://archive.apache.org/dist/zookeeper/zookeeper-3.4.12/zookeeper-3.4.12.tar.gz + +[images] +k8s.gcr.io/kube-apiserver:v1.14.6 +k8s.gcr.io/kube-controller-manager:v1.14.6 +k8s.gcr.io/kube-scheduler:v1.14.6 +k8s.gcr.io/kube-proxy:v1.14.6 +k8s.gcr.io/pause:3.1 +k8s.gcr.io/etcd:3.3.10 +k8s.gcr.io/coredns:1.3.1 +coredns/coredns:1.5.0 +quay.io/coreos/flannel:v0.11.0-amd64 +quay.io/coreos/flannel:v0.11.0 +calico/node:v3.8.1 +calico/pod2daemon-flexvol:v3.8.1 +kubernetesui/dashboard:v2.0.0-beta1 +kubernetesui/metrics-scraper:v1.0.0 +calico/cni:v3.8.1 +calico/kube-controllers:v3.8.1 +jboss/keycloak:4.8.3.Final +rabbitmq:3.7.10 +registry:2 \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/add-repositories.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/add-repositories.sh new file mode 100644 index 0000000000..913baae079 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/add-repositories.sh @@ -0,0 +1,22 @@ +#!/bin/bash -eu + +wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add - +echo "deb https://artifacts.elastic.co/packages/oss-6.x/apt stable main" | tee /etc/apt/sources.list.d/elastic-6.x.list + +wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | apt-key add - +echo "deb [arch=amd64] https://packages.elastic.co/curator/5/debian stable main" | tee /etc/apt/sources.list.d/elastic-curator-6.x.list + +wget -qO - https://packages.grafana.com/gpg.key | apt-key add - +echo "deb https://packages.grafana.com/oss/deb stable main" | tee /etc/apt/sources.list.d/grafana.list + +wget -qO - https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - +echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list + +wget -qO - https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | apt-key add - +echo "deb http://dl.bintray.com/rabbitmq-erlang/debian bionic erlang-21.x" | tee /etc/apt/sources.list.d/erlang-21.x.list +echo "deb https://dl.bintray.com/rabbitmq/debian bionic main" | tee /etc/apt/sources.list.d/rabbitmq.list + +wget -qO - https://download.docker.com/linux/ubuntu/gpg | apt-key add - +echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" | tee /etc/apt/sources.list.d/docker-ce.list + +apt update diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/common.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/common.sh new file mode 100644 index 0000000000..f115e98eae --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/common.sh @@ -0,0 +1,81 @@ +# this file is just a bunch of functions meant to be called from other scripts + + +usage() { + echo "usage: ./$(basename $0) " + echo " ./$(basename $0) /tmp/downloads" + [ -z "$1" ] || exit "$1" +} + +echol() { + echo -e "$1" | tee --append $logfile +} + +# params: +remove_file() { + local file_path="$1" + + echol "Removing file: $file_path" + rm -f "$file_path" || exit_with_error "Command failed: rm -f \"$file_path\"" +} + +# params: +create_directory() { + local dir_path="$1" + + if [[ ! -d "$dir_path" ]]; then + mkdir -p $dir_path + fi +} + +# params: +# todo: skip on existing (maybe when checksum is correct?) +download_image() { + local image_name="$1" + local dest_dir="$2" + + local splited_image=(${image_name//:/ }) + local repository=${splited_image[0]} + local tag=${splited_image[1]} + local repo_basename=$(basename -- "$repository") + local dst_image="${dest_dir}/${repo_basename}-${tag}.tar" + + #[[ ! -f $dst_image ]] || remove_file "$dst_image" + if [[ -f ${dst_image} ]]; then + echo "Image: "${dst_image}" already exists. Skipping..." + else + local tmp_file=$(mktemp) + echo "Downloading image: $1" + echo "Skopeo command is: ./skopeo_linux --insecure-policy copy docker://{$image_name} docker-archive:${dst_image}:${repository}:${tag}" + # use temporary file for downloading to be safe from sudden interruptions (network, ctrl+c) + ./skopeo_linux --insecure-policy copy docker://${image_name} docker-archive:${tmp_file}:${repository}:${tag} && chmod 644 ${tmp_file} && mv ${tmp_file} ${dst_image} + fi +} + +# params: +download_file() { + local file_url="$1" + local dest_dir="$2" + + local file_name=$(basename "$file_url") + local dest_path="$dest_dir/$file_name" + + # wget with --timestamping sometimes failes on AWS with ERROR 403: Forbidden + # so we remove existing file to overwrite it + + # remove old files to force redownload after a while + # just a precaution so --continue won't append and corrupt files localy if file is updated on server without name change + if [[ $(find ${dest_path} -mmin +60 -print) ]]; then + echol "File ${dest_path} older than 1h, redownloading..." + remove_file "$dest_path" + fi + + echol "Downloading file: $file" + + # --no-use-server-timestamps - we don't use --timestamping and we need to expire files somehow + # --continue - don't download the same file multiple times, gracefully skip if file is fully downloaded + wget --no-use-server-timestamps --continue --show-progress --directory-prefix="${dest_dir}" "${file_url}" + + #wget --no-verbose --directory-prefix="$dest_dir" "$file_url" || + #exit_with_error "Command failed: wget --no-verbose --directory-prefix=\"$dest_dir\" \"$file_url\"" +} diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/download-requirements.sh new file mode 100644 index 0000000000..9753ced55a --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/ubuntu-18.04/download-requirements.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +set -euo pipefail + +if [[ $# -lt 1 ]]; then + usage + exit +fi + +if [[ "$EUID" -ne 0 ]]; then + echo "err: this script must be run as root" + exit +fi + +script_path="$( cd "$(dirname "$0")" ; pwd -P )" +input_file="${script_path}/requirements.txt" +dst_dir=$(readlink -m $1) # beautify input path - remove double slashes if occurs +dst_dir_packages="${dst_dir}/packages" +dst_dir_files="${dst_dir}/files" +dst_dir_images="${dst_dir}/images" +deplist="${script_path}/.dependencies" +logfile="${script_path}/log" +download_cmd="apt-get download" +add_repos="${script_path}/add-repositories.sh" + +# to download everything add "--recurse" here: +deplist_cmd() { + apt-cache depends --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --no-pre-depends $1 +} + +# source common functions +. "${script_path}/common.sh" + +repos_backup_file="/tmp/epi-repository-setup-scripts/enable-system-repos.sh" +# restore system repositories in case they're missing if ansible role gets interrupted +if [[ ! -f /etc/apt/sources.list ]]; then + if [[ -f /var/tmp/enabled-system-repos.tar ]] && [[ -f ${repos_backup_file} ]]; then + echol "OS repositories seems missing, restoring..." + ${repos_backup_file} + else + echol "/etc/apt/sources.list seems missing, you either know what you're doing or you need to fix your repositories" + fi +fi + +# install prerequisites which might be missing +apt install -y wget gpg + +# some quick sanity check +echol "Dependency list: ${deplist}" +echol "Command used to download packages: ${download_cmd}" +echol "Destination directory for packages: ${dst_dir_packages}" + +# make sure destination dir exists +mkdir -p "${dst_dir_packages}" +mkdir -p "${dst_dir_files}" +mkdir -p "${dst_dir_images}" + +# add 3rd party repositories +. ${add_repos} + +# parse the input file, separete by tags: [packages], [files], [images] +packages=$(awk '/^$/ || /^#/ {next}; /\[packages\]/ {f=1; next}; /^\[/ {f=0}; f {print $0}' "${input_file}") +files=$(awk '/^$/ || /^#/ {next}; /\[files\]/ {f=1; next}; /^\[/ {f=0}; f {print $0}' "${input_file}") +images=$(awk '/^$/ || /^#/ {next}; /\[images\]/ {f=1; next}; /^\[/ {f=0}; f {print $0}' "${input_file}") + +printf "\n" + +# clear list of cached dependencies if .dependencies is older than 15 minutes +find "$script_path" -type f -wholename "${deplist}" -mmin +15 -exec rm "${deplist}" \; +# clear list of cached dependencies if requirements.txt was recently edited +find "$script_path" -type f -wholename "$input_file" -mmin -1 -exec rm "${deplist}" \; + +# PACKAGES +# if dependency list doesn't exist or is zero size then resolve dependency and store them in a deplist file +if [[ ! -f ${deplist} ]] || [[ ! -s ${deplist} ]] ; then + # clean dependency list if process gets interrupted + trap "rm -f ${deplist}; echol 'Dependency resolution interrupted, cleaning cache file'" SIGINT SIGTERM + echo Resolving dependencies to download. This might take a while and will be cached in ${deplist} + while IFS= read -r package; do + echol "Package read from requirements file: $package" + # if package has a specified version e.g. "name 1.0" store it as "name=1.0*" for compatibility with "apt-get download" + package=$(echo ${package} | awk '{if($2 != "") {print $1 "=" $2 "*"} else {print $1}}') + echol "Package to download: $package" + # store package itself in the list of dependencies... + echol "${package}" >> "${deplist}" + # .. and create depency list for the package + # (names only for dependencies, no version check here, not necessary as most dependencies are backward-compatible) + dependencies=$(deplist_cmd "${package}" | awk '/Depends/ && !/ Packages.gz && cd - + echo "deb [trusted=yes] file:${EPI_REPO_SERVER_PATH}/packages ./" > /etc/apt/sources.list.d/epilocal.list + apt update --assume-no # workaround for botched docker repository https://github.com/docker/for-linux/issues/812 + apt -y install apache2 dpkg-dev + rm -f /etc/apt/sources.list.d/epilocal.list + rm -f ${EPI_REPO_SERVER_PATH}/packages/Packages.gz + apt update --assume-no +else + apt -y install apache2 dpkg-dev +fi + +systemctl start apache2 + +# -m is important because it allow same packages with different versions +# 'cd' is needed here becuase 'dpkg-scanpackages' prepends path to "Filename" field in Packages.gz, otherwise it would break package URL for apt +cd /var/www/html/epirepo/packages && dpkg-scanpackages -m . | gzip -9c > Packages.gz diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/disable-repository-server.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/disable-repository-server.sh new file mode 100644 index 0000000000..ff682636f1 --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/disable-repository-server.sh @@ -0,0 +1,4 @@ +#!/bin/bash -eu + +systemctl stop apache2 +systemctl disable apache2 \ No newline at end of file diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/dpkg-scanpackages b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/dpkg-scanpackages new file mode 100644 index 0000000000..05710ae69c --- /dev/null +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/server/Debian/dpkg-scanpackages @@ -0,0 +1,295 @@ +#!/usr/bin/perl +# +# dpkg-scanpackages +# +# Copyright © 2006-2015 Guillem Jover +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use warnings; +use strict; + +use Getopt::Long qw(:config posix_default bundling no_ignorecase); +use List::Util qw(none); +use File::Find; + +use Dpkg (); +use Dpkg::Gettext; +use Dpkg::ErrorHandling; +use Dpkg::Control; +use Dpkg::Version; +use Dpkg::Checksums; +use Dpkg::Compression::FileHandle; + +textdomain('dpkg-dev'); + +# Do not pollute STDOUT with info messages +report_options(info_fh => \*STDERR); + +my (@samemaint, @changedmaint); +my @spuriousover; +my %packages; +my %overridden; +my %hash; + +my %options = (help => sub { usage(); exit 0; }, + version => sub { version(); exit 0; }, + type => undef, + arch => undef, + hash => undef, + multiversion => 0, + 'extra-override'=> undef, + medium => undef, + ); + +my @options_spec = ( + 'help|?', + 'version', + 'type|t=s', + 'arch|a=s', + 'hash|h=s', + 'multiversion|m!', + 'extra-override|e=s', + 'medium|M=s', +); + +sub version { + printf g_("Debian %s version %s.\n"), $Dpkg::PROGNAME, $Dpkg::PROGVERSION; +} + +sub usage { + printf g_( +"Usage: %s [