diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 6ac8e0b43..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,68 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# ******** NOTE ******** - -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '20 15 * * 0' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 8494815e9..c1cf615fc 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -16,7 +16,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: golangci-lint - uses: reviewdog/action-golangci-lint@v1 + uses: reviewdog/action-golangci-lint@v2 with: github_token: ${{ secrets.GITHUB_TOKEN }} tool_name: golangci-lint diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..21c8e28ae --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,38 @@ +name: "tagged-release" +on: + workflow_dispatch: + inputs: + version: + description: Bump Version + required: true +jobs: + tagged-release: + name: "Tagged Release" + runs-on: "ubuntu-latest" + + steps: + - uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + - name: Test + run: go build -v && go test ./... + - name: Build for linux + run: go build -o terraformer-all-linux-amd64 + - name: Build for mac + run: GOOS=darwin go build -o terraformer-all-darwin-amd64 + - name: Build for mac Apple Silicon + run: GOOS=darwin GOARCH=arm64 go build -o terraformer-all-darwin-arm64 + - name: Build for windows + run: GOOS=windows go build -o terraformer-all-windows-amd64 + - name: Build for all providers + run: go run build/multi-build/main.go + + - uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: ${{ github.event.inputs.version }} + prerelease: false + files: | + terraformer-* diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 000000000..88cf4faed --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,17 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v4 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + days-before-issue-stale: 60 + days-before-issue-close: 7 + days-before-pr-close: -1 \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f44ad2952..43e2ffb13 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,20 +7,21 @@ on: pull_request: branches: - master + - develop jobs: test: strategy: matrix: - go-version: [1.15.x] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} steps: + - uses: actions/checkout@v2 - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.14 - - name: Checkout code - uses: actions/checkout@v2 + go-version: 1.17 + - name: Go Mod Tidy + run: go mod tidy - name: Test - run: go build -v && go test ./... \ No newline at end of file + run: go build -v && go test ./... diff --git a/.gitignore b/.gitignore index 36f39ae83..416cd73a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ .idea generated -terraformer +terraformer* +cmd/tmp .DS_Store .terraform .vscode terraform.tfstate terraform.tfstate.backup init.tf -vendor \ No newline at end of file +vendor diff --git a/README.md b/README.md index e160fdc5e..1215ed753 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # Terraformer -[![Build Status](https://travis-ci.com/GoogleCloudPlatform/terraformer.svg?branch=master)](https://travis-ci.com/GoogleCloudPlatform/terraformer) +[![tests](https://github.com/GoogleCloudPlatform/terraformer/actions/workflows/test.yml/badge.svg)](https://github.com/GoogleCloudPlatform/terraformer/actions/workflows/test.yml) +[![linter](https://github.com/GoogleCloudPlatform/terraformer/actions/workflows/linter.yml/badge.svg)](https://github.com/GoogleCloudPlatform/terraformer/actions/workflows/linter.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/GoogleCloudPlatform/terraformer)](https://goreportcard.com/report/github.com/GoogleCloudPlatform/terraformer) [![AUR package](https://img.shields.io/aur/version/terraformer)](https://aur.archlinux.org/packages/terraformer/) +[![Homebrew](https://img.shields.io/badge/dynamic/json.svg?url=https://formulae.brew.sh/api/formula/terraformer.json&query=$.versions.stable&label=homebrew)](https://formulae.brew.sh/formula/terraformer) A CLI tool that generates `tf`/`json` and `tfstate` files based on existing infrastructure (reverse Terraform). @@ -10,47 +12,65 @@ A CLI tool that generates `tf`/`json` and `tfstate` files based on existing infr * Disclaimer: This is not an official Google product * Created by: Waze SRE -![Waze SRE logo](docs/waze-sre-logo.png) +![Waze SRE logo](assets/waze-sre-logo.png) # Table of Contents - +- [Demo GCP](#demo-gcp) - [Capabilities](#capabilities) - [Installation](#installation) -- [Supported Providers](/providers) +- [Supported Providers](/docs) * Major Cloud - * [Google Cloud](#use-with-gcp) - * [AWS](#use-with-aws) - * [Azure](#use-with-azure) - * [AliCloud](#use-with-alicloud) + * [Google Cloud](/docs/gcp.md) + * [AWS](/docs/aws.md) + * [Azure](/docs/azure.md) + * [AliCloud](/docs/alicloud.md) + * [IBM Cloud](/docs/ibmcloud.md) * Cloud - * [DigitalOcean](#use-with-digitalocean) - * [Fastly](#use-with-fastly) - * [Heroku](#use-with-heroku) - * [Linode](#use-with-linode) - * [NS1](#use-with-ns1) - * [OpenStack](#use-with-openstack) - * [Vultr](#use-with-vultr) - * [Yandex.Cloud](#use-with-yandex) + * [DigitalOcean](/docs/digitalocean.md) + * [Equinix Metal](/docs/equinixmetal.md) + * [Fastly](/docs/fastly.md) + * [Heroku](/docs/heroku.md) + * [Linode](/docs/linode.md) + * [NS1](/docs/ns1.md) + * [OpenStack](/docs/openstack.md) + * [TencentCloud](/docs/tencentcloud.md) + * [Vultr](/docs/vultr.md) + * [Yandex.Cloud](/docs/yandex.md) * Infrastructure Software - * [Kubernetes](#use-with-kubernetes) - * [OctopusDeploy](#use-with-octopusdeploy) - * [RabbitMQ](#use-with-rabbitmq) + * [Kubernetes](/docs/kubernetes.md) + * [OctopusDeploy](/docs/octopus.md) + * [RabbitMQ](/docs/rabbitmq.md) * Network - * [Cloudflare](#use-with-cloudflare) + * [Cloudflare](/docs/cloudflare.md) + * [PAN-OS](/docs/panos.md) * VCS - * [GitHub](#use-with-github) + * [Azure DevOps](/docs/azuredevops.md) + * [GitHub](/docs/github.md) + * [Gitlab](/docs/gitlab.md) * Monitoring & System Management - * [Datadog](#use-with-datadog) - * [New Relic](#use-with-new-relic) + * [Datadog](/docs/datadog.md) + * [New Relic](/docs/relic.md) + * [Mackerel](/docs/mackerel.md) + * [PagerDuty](/docs/pagerduty.md) + * [Opsgenie](/docs/opsgenie.md) * Community - * [Keycloak](#use-with-keycloak) - * [Logz.io](#use-with-logzio) - * [Commercetools](#use-with-commercetools) - * [Mikrotik](#use-with-mikrotik) - * [GmailFilter](#use-with-gmailfilter) + * [Keycloak](/docs/keycloak.md) + * [Logz.io](/docs/logz.md) + * [Commercetools](/docs/commercetools.md) + * [Mikrotik](/docs/mikrotik.md) + * [Xen Orchestra](/docs/xen.md) + * [GmailFilter](/docs/gmailfilter.md) + * [Grafana](/docs/grafana.md) + * [Vault](/docs/vault.md) + * Identity + * [Okta](/docs/okta.md) - [Contributing](#contributing) - [Developing](#developing) - [Infrastructure](#infrastructure) +- [Stargazers over time](#stargazers-over-time) + +## Demo GCP +[![asciicast](https://asciinema.org/a/243961.svg)](https://asciinema.org/a/243961) ## Capabilities @@ -108,6 +128,12 @@ To import resources from all services, use `--resources="*"` . If you want to ex Filters are a way to choose which resources `terraformer` imports. It's possible to filter resources by its identifiers or attributes. Multiple filtering values are separated by `:`. If an identifier contains this symbol, value should be wrapped in `'` e.g. `--filter=resource=id1:'project:dataset_id'`. Identifier based filters will be executed before Terraformer will try to refresh remote state. +Use `Type` when you need to filter only one of several types of resources. Multiple filters can be combined when importing different resource types. An example would be importing all AWS security groups from a specific AWS VPC: +``` +terraformer import aws -r sg,vpc --filter Type=sg;Name=vpc_id;Value=VPC_ID --filter Type=vpc;Name=id;Value=VPC_ID +``` +Notice how the `Name` is different for `sg` than it is for `vpc`. + ##### Resource ID Filtering is based on Terraform resource ID patterns. To find valid ID patterns for your resource, check the import part of the [Terraform documentation][terraform-providers]. @@ -121,6 +147,28 @@ terraformer import aws --resources=vpc,subnet --filter=vpc=myvpcid --regions=eu- ``` Will only import the vpc with id `myvpcid`. This form of filters can help when it's necessary to select resources by its identifiers. +##### Field name only + +It is possible to filter by specific field name only. It can be used e.g. when you want to retrieve resources only with a specific tag key. + +Example usage: + +``` +terraformer import aws --resources=s3 --filter="Name=tags.Abc" --regions=eu-west-1 +``` +Will only import the s3 resources that have tag `Abc`. This form of filters can help when the field values are not important from filtering perspective. + +##### Field with dots + +It is possible to filter by a field that contains a dot. + +Example usage: + +``` +terraformer import aws --resources=s3 --filter="Name=tags.Abc.def" --regions=eu-west-1 +``` +Will only import the s3 resources that have tag `Abc.def`. + #### Planning The `plan` command generates a planfile that contains all the resources set to be imported. By modifying the planfile before running the `import` command, you can rename or filter the resources you'd like to import. @@ -155,10 +203,11 @@ It's possible to combine `--compact` `--path-pattern` parameters together. ### Installation From source: -1. Run `git clone ` +1. Run `git clone && cd terraformer/` 2. Run `go mod download` -3. Run `go build -v` for all providers OR build with one provider `go run build/main.go {google,aws,azure,kubernetes and etc}` -4. Run ```terraform init``` against an ```versions.tf``` file to install the plugins required for your platform. For example, if you need plugins for the google provider, ```versions.tf``` should contain: +3. Run `go build -v` for all providers OR build with one provider +`go run build/main.go {google,aws,azure,kubernetes,etc}` +4. Run ```terraform init``` against a ```versions.tf``` file to install the plugins required for your platform. For example, if you need plugins for the google provider, ```versions.tf``` should contain: ``` terraform { @@ -199,6 +248,7 @@ sudo mv terraformer-${PROVIDER}-darwin-amd64 /usr/local/bin/terraformer If you want to use a package manager: - [Homebrew](https://brew.sh/) users can use `brew install terraformer`. +- [MacPorts](https://www.macports.org/) users can use `sudo port install terraformer`. - [Chocolatey](https://chocolatey.org/) users can use `choco install terraformer`. Links to download Terraform Providers: @@ -209,11 +259,10 @@ Links to download Terraform Providers: * Alicloud provider >1.57.1 - [here](https://releases.hashicorp.com/terraform-provider-alicloud/) * Cloud * DigitalOcean provider >1.9.1 - [here](https://releases.hashicorp.com/terraform-provider-digitalocean/) - * Fastly provider >0.16.1 - [here](https://releases.hashicorp.com/terraform-provider-fastly/) * Heroku provider >2.2.1 - [here](https://releases.hashicorp.com/terraform-provider-heroku/) * Linode provider >1.8.0 - [here](https://releases.hashicorp.com/terraform-provider-linode/) - * NS1 provider >1.8.3 - [here](https://releases.hashicorp.com/terraform-provider-ns1/) * OpenStack provider >1.21.1 - [here](https://releases.hashicorp.com/terraform-provider-openstack/) + * TencentCloud provider >1.50.0 - [here](https://releases.hashicorp.com/terraform-provider-tencentcloud/) * Vultr provider >1.0.5 - [here](https://releases.hashicorp.com/terraform-provider-vultr/) * Yandex provider >0.42.0 - [here](https://releases.hashicorp.com/terraform-provider-yandex/) * Infrastructure Software @@ -221,1293 +270,30 @@ Links to download Terraform Providers: * RabbitMQ provider >=1.1.0 - [here](https://releases.hashicorp.com/terraform-provider-rabbitmq/) * Network * Cloudflare provider >1.16 - [here](https://releases.hashicorp.com/terraform-provider-cloudflare/) + * Fastly provider >0.16.1 - [here](https://releases.hashicorp.com/terraform-provider-fastly/) + * NS1 provider >1.8.3 - [here](https://releases.hashicorp.com/terraform-provider-ns1/) + * PAN-OS provider >= 1.8.3 - [here](https://github.com/PaloAltoNetworks/terraform-provider-panos) * VCS * GitHub provider >=2.2.1 - [here](https://releases.hashicorp.com/terraform-provider-github/) * Monitoring & System Management * Datadog provider >2.1.0 - [here](https://releases.hashicorp.com/terraform-provider-datadog/) - * New Relic provider >1.5.0 - [here](https://releases.hashicorp.com/terraform-provider-newrelic/) + * New Relic provider >2.0.0 - [here](https://releases.hashicorp.com/terraform-provider-newrelic/) + * Mackerel provider > 0.0.6 - [here](https://github.com/mackerelio-labs/terraform-provider-mackerel) + * Pagerduty >=1.9 - [here](https://releases.hashicorp.com/terraform-provider-pagerduty/) + * Opsgenie >= 0.6.0 [here](https://releases.hashicorp.com/terraform-provider-opsgenie/) * Community * Keycloak provider >=1.19.0 - [here](https://github.com/mrparkers/terraform-provider-keycloak/) * Logz.io provider >=1.1.1 - [here](https://github.com/jonboydell/logzio_terraform_provider/) * Commercetools provider >= 0.21.0 - [here](https://github.com/labd/terraform-provider-commercetools) - * Mikrotik provider >= 0.2.2 - [here](https://github.com/labd/terraform-provider-commercetools) + * Mikrotik provider >= 0.2.2 - [here](https://github.com/ddelnano/terraform-provider-mikrotik) + * Xen Orchestra provider >= 0.18.0 - [here](https://github.com/ddelnano/terraform-provider-xenorchestra) * GmailFilter provider >= 1.0.1 - [here](https://github.com/yamamoto-febc/terraform-provider-gmailfilter) + * Vault provider - [here](https://github.com/hashicorp/terraform-provider-vault) Information on provider plugins: https://www.terraform.io/docs/configuration/providers.html -### Use with GCP - -[![asciicast](https://asciinema.org/a/243961.svg)](https://asciinema.org/a/243961) - -Example: - -``` -terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --connect=true --regions=europe-west1,europe-west4 --projects=aaa,fff -terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --filter=compute_firewall=rule1:rule2:rule3 --regions=europe-west1 --projects=aaa,fff -``` - -For google-beta provider: - -``` -terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --regions=europe-west4 --projects=aaa --provider-type beta -``` - -List of supported GCP services: - -* `addresses` - * `google_compute_address` -* `autoscalers` - * `google_compute_autoscaler` -* `backendBuckets` - * `google_compute_backend_bucket` -* `backendServices` - * `google_compute_backend_service` -* `bigQuery` - * `google_bigquery_dataset` - * `google_bigquery_table` -* `cloudFunctions` - * `google_cloudfunctions_function` -* `cloudsql` - * `google_sql_database_instance` - * `google_sql_database` -* `dataProc` - * `google_dataproc_cluster` -* `disks` - * `google_compute_disk` -* `externalVpnGateways` - * `google_compute_external_vpn_gateway` -* `dns` - * `google_dns_managed_zone` - * `google_dns_record_set` -* `firewall` - * `google_compute_firewall` -* `forwardingRules` - * `google_compute_forwarding_rule` -* `gcs` - * `google_storage_bucket` - * `google_storage_bucket_acl` - * `google_storage_default_object_acl` - * `google_storage_bucket_iam_binding` - * `google_storage_bucket_iam_member` - * `google_storage_bucket_iam_policy` - * `google_storage_notification` -* `gke` - * `google_container_cluster` - * `google_container_node_pool` -* `globalAddresses` - * `google_compute_global_address` -* `globalForwardingRules` - * `google_compute_global_forwarding_rule` -* `healthChecks` - * `google_compute_health_check` -* `httpHealthChecks` - * `google_compute_http_health_check` -* `httpsHealthChecks` - * `google_compute_https_health_check` -* `iam` - * `google_project_iam_custom_role` - * `google_project_iam_member` - * `google_service_account` -* `images` - * `google_compute_image` -* `instanceGroupManagers` - * `google_compute_instance_group_manager` -* `instanceGroups` - * `google_compute_instance_group` -* `instanceTemplates` - * `google_compute_instance_template` -* `instances` - * `google_compute_instance` -* `interconnectAttachments` - * `google_compute_interconnect_attachment` -* `kms` - * `google_kms_key_ring` - * `google_kms_crypto_key` -* `logging` - * `google_logging_metric` -* `memoryStore` - * `google_redis_instance` -* `monitoring` - * `google_monitoring_alert_policy` - * `google_monitoring_group` - * `google_monitoring_notification_channel` - * `google_monitoring_uptime_check_config` -* `networks` - * `google_compute_network` -* `packetMirrorings` - * `google_compute_packet_mirroring` -* `nodeGroups` - * `google_compute_node_group` -* `nodeTemplates` - * `google_compute_node_template` -* `project` - * `google_project` -* `pubsub` - * `google_pubsub_subscription` - * `google_pubsub_topic` -* `regionAutoscalers` - * `google_compute_region_autoscaler` -* `regionBackendServices` - * `google_compute_region_backend_service` -* `regionDisks` - * `google_compute_region_disk` -* `regionHealthChecks` - * `google_compute_region_health_check` -* `regionInstanceGroups` - * `google_compute_region_instance_group` -* `regionSslCertificates` - * `google_compute_region_ssl_certificate` -* `regionTargetHttpProxies` - * `google_compute_region_target_http_proxy` -* `regionTargetHttpsProxies` - * `google_compute_region_target_https_proxy` -* `regionUrlMaps` - * `google_compute_region_url_map` -* `reservations` - * `google_compute_reservation` -* `resourcePolicies` - * `google_compute_resource_policy` -* `regionInstanceGroupManagers` - * `google_compute_region_instance_group_manager` -* `routers` - * `google_compute_router` -* `routes` - * `google_compute_route` -* `schedulerJobs` - * `google_cloud_scheduler_job` -* `securityPolicies` - * `google_compute_security_policy` -* `sslCertificates` - * `google_compute_managed_ssl_certificate` -* `sslPolicies` - * `google_compute_ssl_policy` -* `subnetworks` - * `google_compute_subnetwork` -* `targetHttpProxies` - * `google_compute_target_http_proxy` -* `targetHttpsProxies` - * `google_compute_target_https_proxy` -* `targetInstances` - * `google_compute_target_instance` -* `targetPools` - * `google_compute_target_pool` -* `targetSslProxies` - * `google_compute_target_ssl_proxy` -* `targetTcpProxies` - * `google_compute_target_tcp_proxy` -* `targetVpnGateways` - * `google_compute_vpn_gateway` -* `urlMaps` - * `google_compute_url_map` -* `vpnTunnels` - * `google_compute_vpn_tunnel` - -Your `tf` and `tfstate` files are written by default to -`generated/gcp/zone/service`. - -### Use with AWS - -Example: - -``` - terraformer import aws --resources=vpc,subnet --connect=true --regions=eu-west-1 --profile=prod - terraformer import aws --resources=vpc,subnet --filter=vpc=vpc_id1:vpc_id2:vpc_id3 --regions=eu-west-1 -``` - -#### Profiles support - -AWS configuration including environmental variables, shared credentials file (\~/.aws/credentials), and shared config file (\~/.aws/config) will be loaded by the tool by default. To use a specific profile, you can use the following command: - -``` -terraformer import aws --resources=vpc,subnet --regions=eu-west-1 --profile=prod -``` - -You can also provide no regions when importing resources: -``` -terraformer import aws --resources=cloudfront --profile=prod -``` -In that case terraformer will not know with which region resources are associated with and will not assume any region. That scenario is useful in case of global resources (e.g. CloudFront distributions or Route 53 records) and when region is passed implicitly through environmental variables or metadata service. - -#### Supported services - -* `accessanalyzer` - * `aws_accessanalyzer_analyzer` -* `acm` - * `aws_acm_certificate` -* `alb` (supports ALB and NLB) - * `aws_lb` - * `aws_lb_listener` - * `aws_lb_listener_rule` - * `aws_lb_listener_certificate` - * `aws_lb_target_group` - * `aws_lb_target_group_attachment` -* `api_gateway` - * `aws_api_gateway_authorizer` - * `aws_api_gateway_documentation_part` - * `aws_api_gateway_gateway_response` - * `aws_api_gateway_integration` - * `aws_api_gateway_integration_response` - * `aws_api_gateway_method` - * `aws_api_gateway_method_response` - * `aws_api_gateway_model` - * `aws_api_gateway_resource` - * `aws_api_gateway_rest_api` - * `aws_api_gateway_stage` - * `aws_api_gateway_usage_plan` - * `aws_api_gateway_vpc_link` -* `appsync` - * `aws_appsync_graphql_api` -* `auto_scaling` - * `aws_autoscaling_group` - * `aws_launch_configuration` - * `aws_launch_template` -* `budgets` - * `aws_budgets_budget` -* `cloud9` - * `aws_cloud9_environment_ec2` -* `cloudfront` - * `aws_cloudfront_distribution` -* `cloudformation` - * `aws_cloudformation_stack` - * `aws_cloudformation_stack_set` - * `aws_cloudformation_stack_set_instance` -* `cloudtrail` - * `aws_cloudtrail` -* `cloudwatch` - * `aws_cloudwatch_dashboard` - * `aws_cloudwatch_event_rule` - * `aws_cloudwatch_event_target` - * `aws_cloudwatch_metric_alarm` -* `codebuild` - * `aws_codebuild_project` -* `codecommit` - * `aws_codecommit_repository` -* `codedeploy` - * `aws_codedeploy_app` -* `codepipeline` - * `aws_codepipeline` - * `aws_codepipeline_webhook` -* `cognito` - * `aws_cognito_identity_pool` - * `aws_cognito_user_pool` -* `customer_gateway` - * `aws_customer_gateway` -* `config` - * `aws_config_config_rule` - * `aws_config_configuration_recorder` - * `aws_config_delivery_channel` -* `datapipeline` - * `aws_datapipeline_pipeline` -* `devicefarm` - * `aws_devicefarm_project` -* `dynamodb` - * `aws_dynamodb_table` -* `ec2_instance` - * `aws_instance` -* `eip` - * `aws_eip` -* `elasticache` - * `aws_elasticache_cluster` - * `aws_elasticache_parameter_group` - * `aws_elasticache_subnet_group` - * `aws_elasticache_replication_group` -* `ebs` - * `aws_ebs_volume` - * `aws_volume_attachment` -* `elastic_beanstalk` - * `aws_elastic_beanstalk_application` - * `aws_elastic_beanstalk_environment` -* `ecs` - * `aws_ecs_cluster` - * `aws_ecs_service` - * `aws_ecs_task_definition` -* `ecr` - * `aws_ecr_lifecycle_policy` - * `aws_ecr_repository` - * `aws_ecr_repository_policy` -* `efs` - * `aws_efs_access_point` - * `aws_efs_file_system` - * `aws_efs_file_system_policy` - * `aws_efs_mount_target` -* `eks` - * `aws_eks_cluster` -* `elb` - * `aws_elb` -* `emr` - * `aws_emr_cluster` - * `aws_emr_security_configuration` -* `eni` - * `aws_network_interface` -* `es` - * `aws_elasticsearch_domain` -* `firehose` - * `aws_kinesis_firehose_delivery_stream` -* `glue` - * `glue_crawler` - * `aws_glue_catalog_database` - * `aws_glue_catalog_table` -* `iam` - * `aws_iam_group` - * `aws_iam_group_policy` - * `aws_iam_group_policy_attachment` - * `aws_iam_instance_profile` - * `aws_iam_policy` - * `aws_iam_role` - * `aws_iam_role_policy` - * `aws_iam_role_policy_attachment` - * `aws_iam_user` - * `aws_iam_user_group_membership` - * `aws_iam_user_policy` - * `aws_iam_user_policy_attachment` -* `igw` - * `aws_internet_gateway` -* `iot` - * `aws_iot_thing` - * `aws_iot_thing_type` - * `aws_iot_topic_rule` - * `aws_iot_role_alias` -* `kinesis` - * `aws_kinesis_stream` -* `kms` - * `aws_kms_key` - * `aws_kms_alias` -* `lambda` - * `aws_lambda_event_source_mapping` - * `aws_lambda_function` - * `aws_lambda_function_event_invoke_config` - * `aws_lambda_layer_version` -* `logs` - * `aws_cloudwatch_log_group` -* `media_package` - * `aws_media_package_channel` -* `media_store` - * `aws_media_store_container` -* `msk` - * `aws_msk_cluster` -* `nat` - * `aws_nat_gateway` -* `nacl` - * `aws_network_acl` -* `organization` - * `aws_organizations_account` - * `aws_organizations_organization` - * `aws_organizations_organizational_unit` - * `aws_organizations_policy` - * `aws_organizations_policy_attachment` -* `qldb` - * `aws_qldb_ledger` -* `rds` - * `aws_db_instance` - * `aws_db_parameter_group` - * `aws_db_subnet_group` - * `aws_db_option_group` - * `aws_db_event_subscription` -* `resourcegroups` - * `aws_resourcegroups_group` -* `route53` - * `aws_route53_zone` - * `aws_route53_record` -* `route_table` - * `aws_route_table` - * `aws_main_route_table_association` - * `aws_route_table_association` -* `s3` - * `aws_s3_bucket` - * `aws_s3_bucket_policy` -* `secretsmanager` - * `aws_secretsmanager_secret` -* `securityhub` - * `aws_securityhub_account` - * `aws_securityhub_member` - * `aws_securityhub_standards_subscription` -* `servicecatalog` - * `aws_servicecatalog_portfolio` -* `ses` - * `aws_ses_configuration_set` - * `aws_ses_domain_identity` - * `aws_ses_email_identity` - * `aws_ses_receipt_rule` - * `aws_ses_receipt_rule_set` - * `aws_ses_template` -* `sfn` - * `aws_sfn_activity` - * `aws_sfn_state_machine` -* `sg` - * `aws_security_group` - * `aws_security_group_rule` (if a rule cannot be inlined) -* `sns` - * `aws_sns_topic` - * `aws_sns_topic_subscription` -* `sqs` - * `aws_sqs_queue` -* `subnet` - * `aws_subnet` -* `swf` - * `aws_swf_domain` -* `transit_gateway` - * `aws_ec2_transit_gateway_route_table` - * `aws_ec2_transit_gateway_vpc_attachment` -* `waf` - * `aws_waf_byte_match_set` - * `aws_waf_geo_match_set` - * `aws_waf_ipset` - * `aws_waf_rate_based_rule` - * `aws_waf_regex_match_set` - * `aws_waf_regex_pattern_set` - * `aws_waf_rule` - * `aws_waf_rule_group` - * `aws_waf_size_constraint_set` - * `aws_waf_sql_injection_match_set` - * `aws_waf_web_acl` - * `aws_waf_xss_match_set` -* `waf_regional` - * `aws_wafregional_byte_match_set` - * `aws_wafregional_geo_match_set` - * `aws_wafregional_ipset` - * `aws_wafregional_rate_based_rule` - * `aws_wafregional_regex_match_set` - * `aws_wafregional_regex_pattern_set` - * `aws_wafregional_rule` - * `aws_wafregional_rule_group` - * `aws_wafregional_size_constraint_set` - * `aws_wafregional_sql_injection_match_set` - * `aws_wafregional_web_acl` - * `aws_wafregional_xss_match_set` -* `vpc` - * `aws_vpc` -* `vpc_peering` - * `aws_vpc_peering_connection` -* `vpn_connection` - * `aws_vpn_connection` -* `vpn_gateway` - * `aws_vpn_gateway` -* `workspaces` - * `aws_workspaces_directory` - * `aws_workspaces_ip_group` - * `aws_workspaces_workspace` -* `xray` - * `aws_xray_sampling_rule` - -#### Global services - -AWS services that are global will be imported without specified region even if several regions will be passed. It is to ensure only one representation of an AWS resource is imported. - -List of global AWS services: -* `budgets` -* `cloudfront` -* `iam` -* `organization` -* `route53` -* `waf` - -#### Attribute filters - -Attribute filters allow filtering across different resource types by its attributes. - -``` -terraformer import aws --resources=ec2_instance,ebs --filter="Name=tags.costCenter;Value=20000:'20001:1'" --regions=eu-west-1 -``` -Will only import AWS EC2 instances along with EBS volumes annotated with tag `costCenter` with values `20000` or `20001:1`. Attribute filters are by default applicable to all resource types although it's possible to specify to what resource type a given filter should be applicable to by providing `Type=` parameter. For example: -``` -terraformer import aws --resources=ec2_instance,ebs --filter=Type=ec2_instance;Name=tags.costCenter;Value=20000:'20001:1' --regions=eu-west-1 -``` -Will work as same as example above with a change the filter will be applicable only to `ec2_instance` resources. - -Due to fact API Gateway generates a lot of resources, it's possible to issue a filtering query to retrieve resources related to a given REST API by tags. To fetch resources related to a REST API resource with a tag `STAGE` and value `dev`, add parameter `--filter="Type=api_gateway_rest_api;Name=tags.STAGE;Value=dev"`. - -#### SQS queues retrieval - -Terraformer uses AWS [ListQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ListQueues.html) API call to fetch available queues. The API is able to return only up to 1000 queues and an additional name prefix should be passed to filter the list results. It's possible to pass `QueueNamePrefix` parameter by environmental variable `SQS_PREFIX`. - -#### Security groups and rules - -Terraformer by default will try to keep rules in security groups as long as no circular dependencies are detected. This approach is implemented to keep the rules as tidy as possible but there can be cases when this behaviour is not desirable (see [GoogleCloudPlatform/terraformer#493](https://github.com/GoogleCloudPlatform/terraformer/issues/493)). To make Terraformer split rules from security groups, add `SPLIT_SG_RULES` environmental variable with any value. - -### Use with Azure -Support [Azure CLI](https://www.terraform.io/docs/providers/azurerm/guides/azure_cli.html), [Service Principal with Client Certificate](https://www.terraform.io/docs/providers/azurerm/guides/service_principal_client_certificate.html) & [Service Principal with Client Secret](https://www.terraform.io/docs/providers/azurerm/guides/service_principal_client_secret.html) - -Example: - -``` -# Using Azure CLI (az login) -export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] - -# Using Service Principal with Client Certificate -export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] -export ARM_CLIENT_ID=[CLIENT_ID] -export ARM_CLIENT_CERTIFICATE_PATH="/path/to/my/client/certificate.pfx" -export ARM_CLIENT_CERTIFICATE_PASSWORD=[CLIENT_CERTIFICATE_PASSWORD] -export ARM_TENANT_ID=[TENANT_ID] - -# Service Principal with Client Secret -export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] -export ARM_CLIENT_ID=[CLIENT_ID] -export ARM_CLIENT_SECRET=[CLIENT_SECRET] -export ARM_TENANT_ID=[TENANT_ID] - -./terraformer import azure -r resource_group -``` - -List of supported Azure resources: - -* `analysis` - * `azurerm_analysis_services_server` -* `app_service` - * `azurerm_app_service` -* `container` - * `azurerm_container_group` - * `azurerm_container_registry` - * `azurerm_container_registry_webhook` -* `cosmosdb` - * `azurerm_cosmosdb_account` - * `azurerm_cosmosdb_sql_container` - * `azurerm_cosmosdb_sql_database` - * `azurerm_cosmosdb_table` -* `database` - * `azurerm_mariadb_configuration` - * `azurerm_mariadb_database` - * `azurerm_mariadb_firewall_rule` - * `azurerm_mariadb_server` - * `azurerm_mariadb_virtual_network_rule` - * `azurerm_mysql_configuration` - * `azurerm_mysql_database` - * `azurerm_mysql_firewall_rule` - * `azurerm_mysql_server` - * `azurerm_mysql_virtual_network_rule` - * `azurerm_postgresql_configuration` - * `azurerm_postgresql_database` - * `azurerm_postgresql_firewall_rule` - * `azurerm_postgresql_server` - * `azurerm_postgresql_virtual_network_rule` - * `azurerm_sql_database` - * `azurerm_sql_active_directory_administrator` - * `azurerm_sql_elasticpool` - * `azurerm_sql_failover_group` - * `azurerm_sql_firewall_rule` - * `azurerm_sql_server` - * `azurerm_sql_virtual_network_rule` -* `disk` - * `azurerm_managed_disk` -* `dns` - * `azurerm_dns_a_record` - * `azurerm_dns_aaaa_record` - * `azurerm_dns_caa_record` - * `azurerm_dns_cname_record` - * `azurerm_dns_mx_record` - * `azurerm_dns_ns_record` - * `azurerm_dns_ptr_record` - * `azurerm_dns_srv_record` - * `azurerm_dns_txt_record` - * `azurerm_dns_zone` -* `load_balancer` - * `azurerm_lb` - * `azurerm_lb_backend_address_pool` - * `azurerm_lb_nat_rule` - * `azurerm_lb_probe` -* `network_interface` - * `azurerm_network_interface` -* `network_security_group` - * `azurerm_network_security_group` -* `private_dns` - * `azurerm_private_dns_a_record` - * `azurerm_private_dns_aaaa_record` - * `azurerm_private_dns_cname_record` - * `azurerm_private_dns_mx_record` - * `azurerm_private_dns_ptr_record` - * `azurerm_private_dns_srv_record` - * `azurerm_private_dns_txt_record` - * `azurerm_private_dns_zone` - * `azurerm_private_dns_zone_virtual_network_link` -* `public_ip` - * `azurerm_public_ip` - * `azurerm_public_ip_prefix` -* `redis` - * `azurerm_redis_cache -* `resource_group` - * `azurerm_resource_group` -* `scaleset` - * `azurerm_virtual_machine_scale_set` -* `security_center` - * `azurerm_security_center_contact` - * `azurerm_security_center_subscription_pricing` -* `storage_account` - * `azurerm_storage_account` - * `azurerm_storage_blob` - * `azurerm_storage_container` -* `virtual_machine` - * `azurerm_virtual_machine` -* `virtual_network` - * `azurerm_virtual_network` - -### Use with AliCloud - -You can either edit your alicloud config directly, (usually it is `~/.aliyun/config.json`) -or run `aliyun configure` and enter the credentials when prompted. - -Terraformer will pick up the profile name specified in the `--profile` parameter. -It defaults to the first config in the config array. - -```sh -terraformer import alicloud --resources=ecs --regions=ap-southeast-3 --profile=default -``` - -List of supported AliCloud resources: - -* `dns` - * `alicloud_dns` - * `alicloud_dns_record` -* `ecs` - * `alicloud_instance` -* `keypair` - * `alicloud_key_pair` -* `nat` - * `alicloud_nat_gateway` -* `pvtz` - * `alicloud_pvtz_zone` - * `alicloud_pvtz_zone_attachment` - * `alicloud_pvtz_zone_record` -* `ram` - * `alicloud_ram_role` - * `alicloud_ram_role_policy_attachment` -* `rds` - * `alicloud_db_instance` -* `sg` - * `alicloud_security_group` - * `alicloud_security_group_rule` -* `slb` - * `alicloud_slb` - * `alicloud_slb_server_group` - * `alicloud_slb_listener` -* `vpc` - * `alicloud_vpc` -* `vswitch` - * `alicloud_vswitch` - -### Use with DigitalOcean - -Example: - -``` -export DIGITALOCEAN_TOKEN=[DIGITALOCEAN_TOKEN] -./terraformer import digitalocean -r project,droplet -``` - -List of supported DigitalOcean resources: - -* `cdn` - * `digitalocean_cdn` -* `certificate` - * `digitalocean_certificate` -* `database_cluster` - * `digitalocean_database_cluster` - * `digitalocean_database_connection_pool` - * `digitalocean_database_db` - * `digitalocean_database_replica` - * `digitalocean_database_user` -* `domain` - * `digitalocean_domain` - * `digitalocean_record` -* `droplet` - * `digitalocean_droplet` -* `droplet_snapshot` - * `digitalocean_droplet_snapshot` -* `firewall` - * `digitalocean_firewall` -* `floating_ip` - * `digitalocean_floating_ip` -* `kubernetes_cluster` - * `digitalocean_kubernetes_cluster` - * `digitalocean_kubernetes_node_pool` -* `loadbalancer` - * `digitalocean_loadbalancer` -* `project` - * `digitalocean_project` -* `ssh_key` - * `digitalocean_ssh_key` -* `tag` - * `digitalocean_tag` -* `volume` - * `digitalocean_volume` -* `volume_snapshot` - * `digitalocean_volume_snapshot` - -### Use with Fastly - -Example: - -``` -export FASTLY_API_KEY=[FASTLY_API_KEY] -export FASTLY_CUSTOMER_ID=[FASTLY_CUSTOMER_ID] -./terraformer import fastly -r service_v1,user -``` - -List of supported Fastly resources: - -* `service_v1` - * `fastly_service_acl_entries_v1` - * `fastly_service_dictionary_items_v1` - * `fastly_service_dynamic_snippet_content_v1` - * `fastly_service_v1` -* `user` - * `fastly_user_v1` - -### Use with Heroku - -Example: - -``` -export HEROKU_EMAIL=[HEROKU_EMAIL] -export HEROKU_API_KEY=[HEROKU_API_KEY] -./terraformer import heroku -r app,addon -``` - -List of supported Heroku resources: - -* `account_feature` - * `heroku_account_feature` -* `addon` - * `heroku_addon` -* `addon_attachment` - * `heroku_addon_attachment` -* `app` - * `heroku_app` -* `app_config_association` - * `heroku_app_config_association` -* `app_feature` - * `heroku_app_feature` -* `app_webhook` - * `heroku_app_webhook` -* `build` - * `heroku_build` -* `cert` - * `heroku_cert` -* `domain` - * `heroku_domain` -* `drain` - * `heroku_drain` -* `formation` - * `heroku_formation` -* `pipeline` - * `heroku_pipeline` -* `pipeline_coupling` - * `heroku_pipeline_coupling` -* `team_collaborator` - * `heroku_team_collaborator` -* `team_member` - * `heroku_team_member` - -### Use with Linode - -Example: - -``` -export LINODE_TOKEN=[LINODE_TOKEN] -./terraformer import linode -r instance -``` - -List of supported Linode resources: - -* `domain` - * `linode_domain` - * `linode_domain_record` -* `image` - * `linode_image` -* `instance` - * `linode_instance` -* `nodebalancer` - * `linode_nodebalancer` - * `linode_nodebalancer_config` - * `linode_nodebalancer_node` -* `rdns` - * `linode_rdns` -* `sshkey` - * `linode_sshkey` -* `stackscript` - * `linode_stackscript` -* `token` - * `linode_token` -* `volume` - * `linode_volume` - -### Use with NS1 - -Example: - -``` -$ export NS1_APIKEY=[NS1_APIKEY] -$ terraformer import ns1 -r zone,monitoringjob,team -``` - -List of supported NS1 resources: - -* `zone` - * `ns1_zone` -* `monitoringjob` - * `ns1_monitoringjob` -* `team` - * `ns1_team` - -### Use with OpenStack - -Example: - -``` - terraformer import openstack --resources=compute,networking --regions=RegionOne -``` -List of supported OpenStack services: - -* `blockstorage` - * `openstack_blockstorage_volume_v1` - * `openstack_blockstorage_volume_v2` - * `openstack_blockstorage_volume_v3` -* `compute` - * `openstack_compute_instance_v2` -* `networking` - * `openstack_networking_secgroup_v2` - * `openstack_networking_secgroup_rule_v2` - -### Use with Vultr - -Example: - -``` -export VULTR_API_KEY=[VULTR_API_KEY] -./terraformer import vultr -r server -``` - -List of supported Vultr resources: - -* `bare_metal_server` - * `vultr_bare_metal_server` -* `block_storage` - * `vultr_block_storage` -* `dns_domain` - * `vultr_dns_domain` - * `vultr_dns_record` -* `firewall_group` - * `vultr_firewall_group` - * `vultr_firewall_rule` -* `network` - * `vultr_network` -* `reserved_ip` - * `vultr_reserved_ip` -* `server` - * `vultr_server` -* `snapshot` - * `vultr_snapshot` -* `ssh_key` - * `vultr_ssh_key` -* `startup_script` - * `vultr_startup_script` -* `user` - * `vultr_user` - -### Use with Yandex - -Example: - -``` -export YC_TOKEN=[YANDEX_CLOUD_OAUTH_TOKEN] -export YC_FOLDER_ID=[YANDEX_FOLDER_ID] -./terraformer import yandex -r subnet -``` - -List of supported Yandex resources: - -* `instance` - * `yandex_compute_instance` -* `disk` - * `yandex_compute_disk` -* `subnet` - * `yandex_vpc_subnet` -* `network` - * `yandex_vpc_network` - -Your `tf` and `tfstate` files are written by default to -`generated/yandex/service`. - -### Use with Kubernetes - -Example: - -``` - terraformer import kubernetes --resources=deployments,services,storageclasses - terraformer import kubernetes --resources=deployments,services,storageclasses --filter=deployment=name1:name2:name3 -``` - -All Kubernetes resources that are currently supported by the Kubernetes provider, are also supported by this module. Here is the list of resources which are currently supported by Kubernetes provider v.1.4: - -* `clusterrolebinding` - * `kubernetes_cluster_role_binding` -* `configmaps` - * `kubernetes_config_map` -* `deployments` - * `kubernetes_deployment` -* `horizontalpodautoscalers` - * `kubernetes_horizontal_pod_autoscaler` -* `limitranges` - * `kubernetes_limit_range` -* `namespaces` - * `kubernetes_namespace` -* `persistentvolumes` - * `kubernetes_persistent_volume` -* `persistentvolumeclaims` - * `kubernetes_persistent_volume_claim` -* `pods` - * `kubernetes_pod` -* `replicationcontrollers` - * `kubernetes_replication_controller` -* `resourcequotas` - * `kubernetes_resource_quota` -* `secrets` - * `kubernetes_secret` -* `services` - * `kubernetes_service` -* `serviceaccounts` - * `kubernetes_service_account` -* `statefulsets` - * `kubernetes_stateful_set` -* `storageclasses` - * `kubernetes_storage_class` - -#### Known issues - -* Terraform Kubernetes provider is rejecting resources with ":" characters in their names (as they don't meet DNS-1123), while it's allowed for certain types in Kubernetes, e.g. ClusterRoleBinding. -* Because Terraform flatmap uses "." to detect the keys for unflattening the maps, some keys with "." in their names are being considered as the maps. -* Since the library assumes empty strings to be empty values (not "0"), there are some issues with optional integer keys that are restricted to be positive. - -### Use with OctopusDeploy - -Example: - -``` -export OCTOPUS_CLI_SERVER=http://localhost:8081/ -export OCTOPUS_CLI_API_KEY=API-CK7DQ8BMJCUUBSHAJCDIATXUO - -terraformer import octopusdeploy --resources=tagsets -``` - -* `accounts` - * `octopusdeploy_account` -* `certificates` - * `octopusdeploy_certificate` -* `environments` - * `octopusdeploy_environment` -* `feeds` - * `octopusdeploy_feed` -* `libraryvariablesets` - * `octopusdeploy_library_variable_set` -* `lifecycle` - * `octopusdeploy_lifecycle` -* `project` - * `octopusdeploy_project` -* `projectgroups` - * `octopusdeploy_project_group` -* `projecttriggers` - * `octopusdeploy_project_deployment_target_trigger` -* `tagsets` - * `octopusdeploy_tag_set` - -### Use with RabbitMQ - -Example: - -``` - export RABBITMQ_SERVER_URL=http://foo.bar.localdomain:15672 - export RABBITMQ_USERNAME=[RABBITMQ_USERNAME] - export RABBITMQ_PASSWORD=[RABBITMQ_PASSWORD] - - terraformer import rabbitmq --resources=vhosts,queues,exchanges - terraformer import rabbitmq --resources=vhosts,queues,exchanges --filter=vhost=name1:name2:name3 -``` - -All RabbitMQ resources that are currently supported by the RabbitMQ provider, are also supported by this module. Here is the list of resources which are currently supported by RabbitMQ provider v.1.1.0: - -* `bindings` - * `rabbitmq_binding` -* `exchanges` - * `rabbitmq_exchange` -* `permissions` - * `rabbitmq_permissions` -* `policies` - * `rabbitmq_policy` -* `queues` - * `rabbitmq_queue` -* `users` - * `rabbitmq_user` -* `vhosts` - * `rabbitmq_vhost` - -### Use with Cloudflare - -Example using a Cloudflare API Key and corresponding email: -``` -export CLOUDFLARE_API_KEY=[CLOUDFLARE_API_KEY] -export CLOUDFLARE_EMAIL=[CLOUDFLARE_EMAIL] -export CLOUDFLARE_ACCOUNT_ID=[CLOUDFLARE_ACCOUNT_ID] - ./terraformer import cloudflare --resources=firewall,dns -``` - -or using a Cloudflare API Token: - -``` -export CLOUDFLARE_API_TOKEN=[CLOUDFLARE_API_TOKEN] -export CLOUDFLARE_ACCOUNT_ID=[CLOUDFLARE_ACCOUNT_ID] - ./terraformer import cloudflare --resources=firewall,dns -``` - -List of supported Cloudflare services: - -* `access` - * `cloudflare_access_application` -* `dns` - * `cloudflare_zone` - * `cloudflare_record` -* `firewall` - * `cloudflare_access_rule` - * `cloudflare_filter` - * `cloudflare_firewall_rule` - * `cloudflare_zone_lockdown` - * `cloudflare_rate_limit` -* `page_rule` - * `cloudflare_page_rule` -* `account_member` - * `cloudflare_account_member` - -### Use with GitHub - -Example: - -``` - ./terraformer import github --organizations=YOUR_ORGANIZATION --resources=repositories --token=YOUR_TOKEN // or GITHUB_TOKEN in env - ./terraformer import github --organizations=YOUR_ORGANIZATION --resources=repositories --filter=repository=id1:id2:id4 --token=YOUR_TOKEN // or GITHUB_TOKEN in env -``` - -Supports only organizational resources. List of supported resources: - -* `members` - * `github_membership` -* `organization_blocks` - * `github_organization_block` -* `organization_projects` - * `github_organization_project` -* `organization_webhooks` - * `github_organization_webhook` -* `repositories` - * `github_repository` - * `github_repository_webhook` - * `github_branch_protection` - * `github_repository_collaborator` - * `github_repository_deploy_key` -* `teams` - * `github_team` - * `github_team_membership` - * `github_team_repository` -* `user_ssh_keys` - * `github_user_ssh_key` - -Notes: -* Terraformer can't get webhook secrets from the GitHub API. If you use a secret token in any of your webhooks, running `terraform plan` will result in a change being detected: -=> `configuration.#: "1" => "0"` in tfstate only. - -### Use with Datadog - -Example: - -``` - ./terraformer import datadog --resources=monitor --api-key=YOUR_DATADOG_API_KEY // or DATADOG_API_KEY in env --app-key=YOUR_DATADOG_APP_KEY // or DATADOG_APP_KEY in env --api-url=DATADOG_API_URL // or DATADOG_HOST in env - ./terraformer import datadog --resources=monitor --filter=monitor=id1:id2:id4 --api-key=YOUR_DATADOG_API_KEY // or DATADOG_API_KEY in env --app-key=YOUR_DATADOG_APP_KEY // or DATADOG_APP_KEY in env -``` - -List of supported Datadog services: - -* `dashboard` - * `datadog_dashboard` -* `downtime` - * `datadog_downtime` -* `monitor` - * `datadog_monitor` -* `screenboard` - * `datadog_screenboard` -* `synthetics` - * `datadog_synthetics_test` -* `timeboard` - * `datadog_timeboard` -* `user` - * `datadog_user` - -### Use with New Relic - -Example: - -``` -NEWRELIC_API_KEY=[API-KEY] -./terraformer import newrelic -r alert,dashboard,infra,synthetics -``` - -List of supported New Relic resources: - -* `alert` - * `newrelic_alert_channel` - * `newrelic_alert_condition` - * `newrelic_alert_policy` -* `dashboard` - * `newrelic_dashboard` -* `infra` - * `newrelic_infra_alert_condition` -* `synthetics` - * `newrelic_synthetics_monitor` - * `newrelic_synthetics_alert_condition` - -### Use with Keycloak - -Example: - -``` - export KEYCLOAK_URL=https://foo.bar.localdomain - export KEYCLOAK_CLIENT_ID=[KEYCLOAK_CLIENT_ID] - export KEYCLOAK_CLIENT_SECRET=[KEYCLOAK_CLIENT_SECRET] - - terraformer import keycloak --resources=realms - terraformer import keycloak --resources=realms --filter=realm=name1:name2:name3 - terraformer import keycloak --resources=realms --targets realmA,realmB -``` - -Here is the list of resources which are currently supported by Keycloak provider v.1.19.0: - -- `realms` - - `keycloak_default_groups` - - `keycloak_group` - - `keycloak_group_memberships` - - `keycloak_group_roles` - - `keycloak_ldap_full_name_mapper` - - `keycloak_ldap_group_mapper` - - `keycloak_ldap_hardcoded_group_mapper` - - `keycloak_ldap_hardcoded_role_mapper` - - `keycloak_ldap_msad_lds_user_account_control_mapper` - - `keycloak_ldap_msad_user_account_control_mapper` - - `keycloak_ldap_user_attribute_mapper` - - `keycloak_ldap_user_federation` - - `keycloak_openid_audience_protocol_mapper` - - `keycloak_openid_client` - - `keycloak_openid_client_default_scopes` - - `keycloak_openid_client_optional_scopes` - - `keycloak_openid_client_scope` - - `keycloak_openid_client_service_account_role` - - `keycloak_openid_full_name_protocol_mapper` - - `keycloak_openid_group_membership_protocol_mapper` - - `keycloak_openid_hardcoded_claim_protocol_mapper` - - `keycloak_openid_hardcoded_group_protocol_mapper` - - `keycloak_openid_hardcoded_role_protocol_mapper` (only for client roles) - - `keycloak_openid_user_attribute_protocol_mapper` - - `keycloak_openid_user_property_protocol_mapper` - - `keycloak_openid_user_realm_role_protocol_mapper` - - `keycloak_openid_user_client_role_protocol_mapper` - - `keycloak_openid_user_session_note_protocol_mapper` - - `keycloak_realm` - - `keycloak_required_action` - - `keycloak_role` - - `keycloak_user` - -### Use with Logz.io - -Example: - -``` - LOGZIO_API_TOKEN=foobar LOGZIO_BASE_URL=https://api-eu.logz.io ./terraformer import logzio -r=alerts,alert_notification_endpoints // Import Logz.io alerts and alert notification endpoints -``` - -List of supported Logz.io resources: - -* `alerts` - * `logzio_alert` -* `alert_notification_endpoints` - * `logzio_endpoint` - -### Use with [Commercetools](https://commercetools.com/de/) - -This provider use the [terraform-provider-commercetools](https://github.com/labd/terraform-provider-commercetools). The terraformer provider was build by [Dustin Deus](https://github.com/StarpTech). - -Example: - -``` -CTP_CLIENT_ID=foo CTP_CLIENT_SCOPE=scope CTP_CLIENT_SECRET=bar CTP_PROJECT_KEY=key ./terraformer plan commercetools -r=types // Only planning -CTP_CLIENT_ID=foo CTP_CLIENT_SCOPE=scope CTP_CLIENT_SECRET=bar CTP_PROJECT_KEY=key ./terraformer import commercetools -r=types // Import commercetools types -``` - -List of supported [commercetools](https://commercetools.com/de/) resources: - -* `api_extension` - * `commercetools_api_extension` -* `channel` - * `commercetools_channel` -* `product_type` - * `commercetools_product_type` -* `shipping_method` - * `commercetools_shipping_method` -* `shipping_zone` - * `commercetools_shipping_zone` -* `state` - * `commercetools_state` -* `store` - * `commercetools_store` -* `subscription` - * `commercetools_subscription` -* `tax_category` - * `commercetools_tax_category` -* `types` - * `commercetools_type` - -### Use with [Mikrotik](https://wiki.mikrotik.com/wiki/Manual:TOC) - -This provider uses the [terraform-provider-mikrotik](https://github.com/ddelnano/terraform-provider-mikrotik). The terraformer provider was build by [Dom Del Nano](https://github.com/ddelnano). - -Example: - -``` -## Warning! You should not expose your mikrotik creds through your bash history. Export them to your shell in a safe way when doing this for real! - -MIKROTIK_HOST=router-hostname:8728 MIKROTIK_USER=username MIKROTIK_PASSWORD=password terraformer import mikrotik -r=dhcp_lease - -# Import only static IPs -MIKROTIK_HOST=router-hostname:8728 MIKROTIK_USER=username MIKROTIK_PASSWORD=password terraformer import mikrotik -r=dhcp_lease --filter='Name=dynamic;Value=false' -``` - -List of supported mikrotik resources: - -* `mikrotik_dhcp_lease` - - -### Use with GmailFilter - -Support [Using Service Accounts](https://github.com/yamamoto-febc/terraform-provider-gmailfilter/blob/master/README.md#using-a-service-accountg-suite-users-only) or [Using Application Default Credentials](https://github.com/yamamoto-febc/terraform-provider-gmailfilter/blob/master/README.md#using-an-application-default-credential). - -Example: - -``` -# Using Service Accounts -export GOOGLE_CREDENTIALS=/path/to/client_secret.json -export IMPERSONATED_USER_EMAIL="foobar@example.com" - -# Using Application Default Credentials -gcloud auth application-default login \ - --client-id-file=client_secret.json \ - --scopes \ -https://www.googleapis.com/auth/gmail.labels,\ -https://www.googleapis.com/auth/gmail.settings.basic - -./terraformer import gmailfilter -r=filter,label -``` - -List of supported GmailFilter resources: - -* `label` - * `gmailfilter_label` -* `filter` - * `gmailfilter_filter` ## Contributing @@ -1569,3 +355,7 @@ Terraforming lacks full coverage for resources - as an example you can see that * terraforming - https://github.com/dtan4/terraforming/blob/master/lib/terraforming/template/tf/s3.erb * official S3 support - https://www.terraform.io/docs/providers/aws/r/s3_bucket.html + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/GoogleCloudPlatform/terraformer.svg)](https://starchart.cc/GoogleCloudPlatform/terraformer) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..ce1f393f6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,4 @@ +To report a security issue, please use http://g.co/vulnz. We use +http://g.co/vulnz for our intake, and do coordination and disclosure here on +GitHub (including using GitHub Security Advisory). The Google Security Team will +respond within 5 working days of your report on g.co/vulnz. diff --git a/docs/waze-sre-logo.png b/assets/waze-sre-logo.png similarity index 100% rename from docs/waze-sre-logo.png rename to assets/waze-sre-logo.png diff --git a/build/multi-build/main.go b/build/multi-build/main.go index 0ab6ef42d..e4dad148d 100644 --- a/build/multi-build/main.go +++ b/build/multi-build/main.go @@ -15,7 +15,7 @@ const fileSuffix = ".go" const packageCmdPath = "cmd" func main() { - //provider := os.Args[1] + // provider := os.Args[1] allProviders := []string{} files, err := ioutil.ReadDir(packageCmdPath) if err != nil { @@ -23,8 +23,8 @@ func main() { } for _, f := range files { if strings.HasPrefix(f.Name(), filePrefix) { - providerName := strings.Replace(f.Name(), filePrefix, "", -1) - providerName = strings.Replace(providerName, fileSuffix, "", -1) + providerName := strings.ReplaceAll(f.Name(), filePrefix, "") + providerName = strings.ReplaceAll(providerName, fileSuffix, "") allProviders = append(allProviders, providerName) } } @@ -48,14 +48,17 @@ func main() { for _, f := range files { if strings.HasPrefix(f.Name(), filePrefix) { if !strings.HasPrefix(f.Name(), filePrefix+provider+fileSuffix) { - providerName := strings.Replace(f.Name(), filePrefix, "", -1) - providerName = strings.Replace(providerName, fileSuffix, "", -1) + providerName := strings.ReplaceAll(f.Name(), filePrefix, "") + providerName = strings.ReplaceAll(providerName, fileSuffix, "") deletedProvider = append(deletedProvider, providerName) } } } // move files for deleted providers - os.MkdirAll(packageCmdPath+"/tmp", os.ModePerm) + err := os.MkdirAll(packageCmdPath+"/tmp", os.ModePerm) + if err != nil { + log.Fatal("err:", err) + } for _, provider := range deletedProvider { err := os.Rename(packageCmdPath+"/"+filePrefix+provider+fileSuffix, packageCmdPath+"/tmp/"+filePrefix+provider+fileSuffix) if err != nil { @@ -65,6 +68,9 @@ func main() { // comment deleted providers in code rootCode, err := ioutil.ReadFile(packageCmdPath + "/root.go") + if err != nil { + log.Fatal("err:", err) + } lines := strings.Split(string(rootCode), "\n") newRootCodeLines := make([]string, len(lines)) for i, line := range lines { @@ -79,7 +85,10 @@ func main() { newRootCodeLines[i] = line } newRootCode := strings.Join(newRootCodeLines, "\n") - ioutil.WriteFile(packageCmdPath+"/root.go", []byte(newRootCode), os.ModePerm) + err = ioutil.WriteFile(packageCmdPath+"/root.go", []byte(newRootCode), os.ModePerm) + if err != nil { + log.Fatal("err:", err) + } // build.... cmd := exec.Command("go", "build", "-v", "-o", binaryName) @@ -94,8 +103,11 @@ func main() { } fmt.Println(outb.String()) - //revert code and files - ioutil.WriteFile(packageCmdPath+"/root.go", []byte(rootCode), os.ModePerm) + // revert code and files + err = ioutil.WriteFile(packageCmdPath+"/root.go", rootCode, os.ModePerm) + if err != nil { + log.Fatal("err:", err) + } for _, provider := range deletedProvider { err := os.Rename(packageCmdPath+"/tmp/"+filePrefix+provider+fileSuffix, "cmd/"+filePrefix+provider+fileSuffix) if err != nil { @@ -104,4 +116,4 @@ func main() { } } } -} \ No newline at end of file +} diff --git a/cmd/import.go b/cmd/import.go index ad16e66f4..27f050978 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -136,7 +136,7 @@ func initOptionsAndWrapper(provider terraformutils.ProviderGenerator, options Im options.Resources = localSlice } - providerWrapper, err := providerwrapper.NewProviderWrapper(provider.GetName(), provider.GetConfig(), options.Verbose, options.RetryCount, options.RetrySleepMs) + providerWrapper, err := providerwrapper.NewProviderWrapper(provider.GetName(), provider.GetConfig(), options.Verbose, map[string]int{"retryCount": options.RetryCount, "retrySleepMs": options.RetrySleepMs}) if err != nil { return nil, options, err } @@ -149,7 +149,7 @@ func initAllServicesResources(providersMapping *terraformutils.ProvidersMapping, var wg sync.WaitGroup wg.Add(numOfResources) - failedServices := make(chan string, numOfResources) + var failedServices []string for _, service := range options.Resources { serviceProvider := providersMapping.AddServiceToProvider(service) @@ -157,14 +157,15 @@ func initAllServicesResources(providersMapping *terraformutils.ProvidersMapping, if err != nil { return err } - go initServiceResourcesWorker(service, serviceProvider, options, providerWrapper, &wg, failedServices) + err = initServiceResources(service, serviceProvider, options, providerWrapper) + if err != nil { + failedServices = append(failedServices, service) + } } - wg.Wait() - close(failedServices) // remove providers that failed to init their service providersMapping.RemoveServices(failedServices) - providersMapping.ProcessResources() + providersMapping.ProcessResources(false) return nil } @@ -190,29 +191,26 @@ func importFromPlan(providerMapping *terraformutils.ProvidersMapping, options Im return ImportFromPlan(providerMapping.GetBaseProvider(), plan) } -func initServiceResourcesWorker(service string, provider terraformutils.ProviderGenerator, - options ImportOptions, providerWrapper *providerwrapper.ProviderWrapper, wg *sync.WaitGroup, failedServices chan string) { +func initServiceResources(service string, provider terraformutils.ProviderGenerator, + options ImportOptions, providerWrapper *providerwrapper.ProviderWrapper) error { log.Println(provider.GetName() + " importing... " + service) err := provider.InitService(service, options.Verbose) if err != nil { - failedServices <- service log.Printf("%s error importing %s, err: %s\n", provider.GetName(), service, err) - wg.Done() - return + return err } provider.GetService().ParseFilters(options.Filter) err = provider.GetService().InitResources() if err != nil { - failedServices <- service log.Printf("%s error initializing resources in service %s, err: %s\n", provider.GetName(), service, err) - wg.Done() - return + return err } provider.GetService().PopulateIgnoreKeys(providerWrapper) provider.GetService().InitialCleanup() log.Println(provider.GetName() + " done importing " + service) - wg.Done() + + return nil } func ImportFromPlan(provider terraformutils.ProviderGenerator, plan *ImportPlan) error { @@ -306,9 +304,9 @@ func printService(provider terraformutils.ProviderGenerator, serviceName string, } variables["data"]["terraform_remote_state"][k] = map[string]interface{}{ "backend": "local", - "config": [1]interface{}{map[string]interface{}{ + "config": map[string]interface{}{ "path": strings.Repeat("../", strings.Count(path, "/")) + strings.ReplaceAll(path, serviceName, k) + "terraform.tfstate", - }}, + }, } } } diff --git a/cmd/provider_cmd_azure.go b/cmd/provider_cmd_azure.go index aab5b3906..dad66fb44 100644 --- a/cmd/provider_cmd_azure.go +++ b/cmd/provider_cmd_azure.go @@ -27,7 +27,7 @@ func newCmdAzureImporter(options ImportOptions) *cobra.Command { Long: "Import current state to Terraform configuration from Azure", RunE: func(cmd *cobra.Command, args []string) error { provider := newAzureProvider() - err := Import(provider, options, []string{}) + err := Import(provider, options, []string{options.ResourceGroup}) if err != nil { return err } @@ -37,6 +37,7 @@ func newCmdAzureImporter(options ImportOptions) *cobra.Command { cmd.AddCommand(listCmd(newAzureProvider())) baseProviderFlags(cmd.PersistentFlags(), &options, "resource_group", "resource_group=name1:name2:name3") + cmd.PersistentFlags().StringVarP(&options.ResourceGroup, "resource-group", "R", "", "") return cmd } diff --git a/cmd/provider_cmd_azuredevops.go b/cmd/provider_cmd_azuredevops.go new file mode 100644 index 000000000..91f9e32b6 --- /dev/null +++ b/cmd/provider_cmd_azuredevops.go @@ -0,0 +1,45 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + azuredevops "github.com/GoogleCloudPlatform/terraformer/providers/azuredevops" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdAzureDevOpsImporter(options ImportOptions) *cobra.Command { + + cmd := &cobra.Command{ + Use: "azuredevops", + Short: "Import current state to Terraform configuration from Azure DevOps", + Long: "Import current state to Terraform configuration from Azure DevOps", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newAzureDevOpsProvider() + err := Import(provider, options, []string{options.ResourceGroup}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newAzureDevOpsProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "project,team,git", "project=name1:name2:name3") + return cmd +} + +func newAzureDevOpsProvider() terraformutils.ProviderGenerator { + return &azuredevops.AzureDevOpsProvider{} +} diff --git a/cmd/provider_cmd_datadog.go b/cmd/provider_cmd_datadog.go index 8fed391b5..3ca119935 100644 --- a/cmd/provider_cmd_datadog.go +++ b/cmd/provider_cmd_datadog.go @@ -20,14 +20,14 @@ import ( ) func newCmdDatadogImporter(options ImportOptions) *cobra.Command { - var apiKey, appKey, apiURL string + var apiKey, appKey, apiURL, validate string cmd := &cobra.Command{ Use: "datadog", Short: "Import current state to Terraform configuration from Datadog", Long: "Import current state to Terraform configuration from Datadog", RunE: func(cmd *cobra.Command, args []string) error { provider := newDataDogProvider() - err := Import(provider, options, []string{apiKey, appKey, apiURL}) + err := Import(provider, options, []string{apiKey, appKey, apiURL, validate}) if err != nil { return err } @@ -39,6 +39,7 @@ func newCmdDatadogImporter(options ImportOptions) *cobra.Command { cmd.PersistentFlags().StringVarP(&apiKey, "api-key", "", "", "YOUR_DATADOG_API_KEY or env param DATADOG_API_KEY") cmd.PersistentFlags().StringVarP(&appKey, "app-key", "", "", "YOUR_DATADOG_APP_KEY or env param DATADOG_APP_KEY") cmd.PersistentFlags().StringVarP(&apiURL, "api-url", "", "", "YOUR_DATADOG_API_URL or env param DATADOG_HOST") + cmd.PersistentFlags().StringVar(&validate, "validate", "", "bool-parsable values only or env param DATADOG_VALIDATE. Enables validation of the provided API and APP keys during provider initialization. Default is true. When false, api_key and app_key won't be checked") return cmd } diff --git a/cmd/provider_cmd_equinixmetal.go b/cmd/provider_cmd_equinixmetal.go new file mode 100644 index 000000000..8ce4195d8 --- /dev/null +++ b/cmd/provider_cmd_equinixmetal.go @@ -0,0 +1,46 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + equinixmetal_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/equinixmetal" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdEquinixMetalImporter(options ImportOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "metal", + Short: "Import current state to Terraform configuration from Equinix Metal", + Long: "Import current state to Terraform configuration from Equinix Metal", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newEquinixMetalProvider() + err := Import(provider, options, []string{}) + if err != nil { + return err + } + return nil + }, + } + + cmd.AddCommand(listCmd(newEquinixMetalProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "project,device", "project=name1:name2:name3") + + return cmd +} + +func newEquinixMetalProvider() terraformutils.ProviderGenerator { + return &equinixmetal_terraforming.EquinixMetalProvider{} +} diff --git a/cmd/provider_cmd_github.go b/cmd/provider_cmd_github.go index 4c4f7b52e..42371a284 100644 --- a/cmd/provider_cmd_github.go +++ b/cmd/provider_cmd_github.go @@ -24,19 +24,20 @@ import ( func newCmdGithubImporter(options ImportOptions) *cobra.Command { token := "" - organizations := []string{} + baseURL := "" + owner := []string{} cmd := &cobra.Command{ Use: "github", Short: "Import current state to Terraform configuration from GitHub", Long: "Import current state to Terraform configuration from GitHub", RunE: func(cmd *cobra.Command, args []string) error { originalPathPattern := options.PathPattern - for _, organization := range organizations { + for _, organization := range owner { provider := newGitHubProvider() options.PathPattern = originalPathPattern options.PathPattern = strings.ReplaceAll(options.PathPattern, "{provider}", "{provider}/"+organization) log.Println(provider.GetName() + " importing organization " + organization) - err := Import(provider, options, []string{organization, token}) + err := Import(provider, options, []string{organization, token, baseURL}) if err != nil { return err } @@ -47,7 +48,8 @@ func newCmdGithubImporter(options ImportOptions) *cobra.Command { cmd.AddCommand(listCmd(newGitHubProvider())) baseProviderFlags(cmd.PersistentFlags(), &options, "repository", "repository=id1:id2:id4") cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "YOUR_GITHUB_TOKEN or env param GITHUB_TOKEN") - cmd.PersistentFlags().StringSliceVarP(&organizations, "organizations", "", []string{}, "") + cmd.PersistentFlags().StringSliceVarP(&owner, "owner", "", []string{}, "") + cmd.PersistentFlags().StringVarP(&baseURL, "base-url", "", "", "") return cmd } diff --git a/cmd/provider_cmd_gitlab.go b/cmd/provider_cmd_gitlab.go new file mode 100644 index 000000000..bbd3a1895 --- /dev/null +++ b/cmd/provider_cmd_gitlab.go @@ -0,0 +1,58 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + "log" + "strings" + + gitLab_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/gitlab" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdGitLabImporter(options ImportOptions) *cobra.Command { + token := "" + baseURL := "" + groups := []string{} + cmd := &cobra.Command{ + Use: "gitlab", + Short: "Import current state to Terraform configuration from GitLab", + Long: "Import current state to Terraform configuration from GitLab", + RunE: func(cmd *cobra.Command, args []string) error { + originalPathPattern := options.PathPattern + for _, group := range groups { + provider := newGitLabProvider() + options.PathPattern = originalPathPattern + options.PathPattern = strings.ReplaceAll(options.PathPattern, "{provider}", "{provider}/"+group) + log.Println(provider.GetName() + " importing group " + group) + err := Import(provider, options, []string{group, token, baseURL}) + if err != nil { + return err + } + } + return nil + }, + } + cmd.AddCommand(listCmd(newGitLabProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "repository", "repository=id1:id2:id4") + cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "YOUR_GITLAB_TOKEN or env param GITLAB_TOKEN") + cmd.PersistentFlags().StringSliceVarP(&groups, "group", "", []string{}, "paths to groups") + cmd.PersistentFlags().StringVarP(&baseURL, "base-url", "", "", "") + return cmd +} + +func newGitLabProvider() terraformutils.ProviderGenerator { + return &gitLab_terraforming.GitLabProvider{} +} diff --git a/cmd/provider_cmd_grafana.go b/cmd/provider_cmd_grafana.go new file mode 100644 index 000000000..3c06b90e1 --- /dev/null +++ b/cmd/provider_cmd_grafana.go @@ -0,0 +1,44 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + "github.com/GoogleCloudPlatform/terraformer/providers/grafana" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdGrafanaImporter(options ImportOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "grafana", + Short: "Import current state to Terraform configuration from Grafana", + Long: "Import current state to Terraform configuration from Grafana", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newGrafanaProvider() + err := Import(provider, options, []string{}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newGrafanaProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "grafana_dashboard", "dashboard=slug1") + return cmd +} + +func newGrafanaProvider() terraformutils.ProviderGenerator { + return &grafana.GrafanaProvider{} +} diff --git a/cmd/provider_cmd_ibm.go b/cmd/provider_cmd_ibm.go new file mode 100644 index 000000000..099aa3ccb --- /dev/null +++ b/cmd/provider_cmd_ibm.go @@ -0,0 +1,51 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + ibm_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/ibm" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdIbmImporter(options ImportOptions) *cobra.Command { + var resourceGroup string + var region string + var cis string + cmd := &cobra.Command{ + Use: "ibm", + Short: "Import current state to Terraform configuration from ibm", + Long: "Import current state to Terraform configuration from ibm", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newIbmProvider() + err := Import(provider, options, []string{resourceGroup, region, cis}) + if err != nil { + return err + } + return nil + }, + } + + cmd.AddCommand(listCmd(newIbmProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "server", "ibm_server=name1:name2:name3") + cmd.PersistentFlags().StringVarP(&resourceGroup, "resource_group", "", "", "resource_group=default") + cmd.PersistentFlags().StringVarP(®ion, "region", "R", "", "region=us-south") + cmd.PersistentFlags().StringVarP(&cis, "cis", "", "", "cis=TestCIS") + return cmd +} + +func newIbmProvider() terraformutils.ProviderGenerator { + return &ibm_terraforming.IBMProvider{} +} diff --git a/cmd/provider_cmd_mackerel.go b/cmd/provider_cmd_mackerel.go new file mode 100644 index 000000000..1d84b1c27 --- /dev/null +++ b/cmd/provider_cmd_mackerel.go @@ -0,0 +1,46 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + mackerel_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/mackerel" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdMackerelImporter(options ImportOptions) *cobra.Command { + var apiKey string + cmd := &cobra.Command{ + Use: "mackerel", + Short: "Import current state to Terraform configuration from Mackerel", + Long: "Import current state to Terraform configuration from Mackerel", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newMackerelProvider() + err := Import(provider, options, []string{apiKey}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newMackerelProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "service,role,aws_integration", "aws_integration=id1:id2:id4") + cmd.PersistentFlags().StringVarP(&apiKey, "api-key", "", "", "YOUR_MACKEREL_API_KEY or env param MACKEREL_API_KEY") + return cmd +} + +func newMackerelProvider() terraformutils.ProviderGenerator { + return &mackerel_terraforming.MackerelProvider{} +} diff --git a/cmd/provider_cmd_newrelic.go b/cmd/provider_cmd_newrelic.go index beb3edc4c..015ca8a12 100644 --- a/cmd/provider_cmd_newrelic.go +++ b/cmd/provider_cmd_newrelic.go @@ -21,13 +21,16 @@ import ( ) func newCmdNewRelicImporter(options ImportOptions) *cobra.Command { + apiKey := "" + accountID := "" + region := "" cmd := &cobra.Command{ Use: "newrelic", Short: "Import current state to Terraform configuration from New Relic", Long: "Import current state to Terraform configuration from New Relic", RunE: func(cmd *cobra.Command, args []string) error { provider := newNewRelicProvider() - err := Import(provider, options, []string{}) + err := Import(provider, options, []string{apiKey, accountID, region}) if err != nil { return err } @@ -36,6 +39,9 @@ func newCmdNewRelicImporter(options ImportOptions) *cobra.Command { } cmd.AddCommand(listCmd(newNewRelicProvider())) + cmd.PersistentFlags().StringVar(&apiKey, "api-key", "", "Your Personal API Key") + cmd.PersistentFlags().StringVar(&accountID, "account-id", "", "Your Account ID") + cmd.PersistentFlags().StringVar(®ion, "region", "US", "") baseProviderFlags(cmd.PersistentFlags(), &options, "alert", "dashboard=id1:id2:id4") return cmd } diff --git a/cmd/provider_cmd_okta.go b/cmd/provider_cmd_okta.go new file mode 100644 index 000000000..db870f129 --- /dev/null +++ b/cmd/provider_cmd_okta.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + "errors" + "os" + + okta_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/okta" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdOktaImporter(options ImportOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "okta", + Short: "Import current State to terraform configuration from okta", + Long: "Import current State to terraform configuration from okta", + RunE: func(cmd *cobra.Command, args []string) error { + token := os.Getenv("OKTA_API_TOKEN") + if len(token) == 0 { + return errors.New("API Token for Okta must be set through `OKTA_API_TOKEN` env var") + } + baseURL := os.Getenv("OKTA_BASE_URL") + if len(baseURL) == 0 { + return errors.New("Base URL for Okta must be set through `OKTA_BASE_URL` env var") + } + orgName := os.Getenv("OKTA_ORG_NAME") + if len(orgName) == 0 { + return errors.New("Org Name for Okta must be set through `OKTA_ORG_NAME` env var") + } + + provider := newOktaProvider() + err := Import(provider, options, []string{orgName, token, baseURL}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newOktaProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "user", "okta_user=user1:user2:user3") + return cmd +} + +func newOktaProvider() terraformutils.ProviderGenerator { + return &okta_terraforming.OktaProvider{} +} diff --git a/cmd/provider_cmd_opsgenie.go b/cmd/provider_cmd_opsgenie.go new file mode 100644 index 000000000..1e2c60e59 --- /dev/null +++ b/cmd/provider_cmd_opsgenie.go @@ -0,0 +1,33 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + opsgenie_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/opsgenie" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +func newCmdOpsgenieImporter(options ImportOptions) *cobra.Command { + var apiKey string + cmd := &cobra.Command{ + Use: "opsgenie", + Short: "Import current state to Terraform configuration from Opsgenie", + Long: "Import current state to Terraform configuration from Opsgenie", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newOpsgenieProvider() + err := Import(provider, options, []string{apiKey}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newOpsgenieProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "user,team", "") + cmd.PersistentFlags().StringVarP(&apiKey, "api-key", "", "", "YOUR_OPSGENIE_API_KEY or env param OPSGENIE_API_KEY") + return cmd +} + +func newOpsgenieProvider() terraformutils.ProviderGenerator { + return &opsgenie_terraforming.OpsgenieProvider{} +} diff --git a/cmd/provider_cmd_pagerduty.go b/cmd/provider_cmd_pagerduty.go new file mode 100644 index 000000000..7e3ebdd0d --- /dev/null +++ b/cmd/provider_cmd_pagerduty.go @@ -0,0 +1,47 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + pagerduty_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/pagerduty" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdPagerDutyImporter(options ImportOptions) *cobra.Command { + token := "" + cmd := &cobra.Command{ + Use: "pagerduty", + Short: "Import current state to Terraform configuration from PagerDuty", + Long: "Import current state to Terraform configuration from PagerDuty", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newPagerDutyProvider() + err := Import(provider, options, []string{token}) + if err != nil { + return err + } + return nil + }, + } + + cmd.AddCommand(listCmd(newPagerDutyProvider())) + cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "env param PAGERDUTY_TOKEN") + baseProviderFlags(cmd.PersistentFlags(), &options, "user", "user=id1:id2:id4") + return cmd +} + +func newPagerDutyProvider() terraformutils.ProviderGenerator { + return &pagerduty_terraforming.PagerDutyProvider{} +} diff --git a/cmd/provider_cmd_panos.go b/cmd/provider_cmd_panos.go new file mode 100644 index 000000000..a8f4a9ef1 --- /dev/null +++ b/cmd/provider_cmd_panos.go @@ -0,0 +1,82 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "log" + "reflect" + "strings" + + panos_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/panos" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdPanosImporter(options ImportOptions) *cobra.Command { + vsys := []string{} + cmd := &cobra.Command{ + Use: "panos", + Short: "Import current state to Terraform configuration from a PAN-OS", + Long: "Import current state to Terraform configuration from a PAN-OS", + RunE: func(cmd *cobra.Command, args []string) error { + var t interface{} + + if len(vsys) == 0 { + var err error + + vsys, t, err = panos_terraforming.GetVsysList() + if err != nil { + return err + } + } else { + c, err := panos_terraforming.Initialize() + if err != nil { + return err + } + + t = reflect.TypeOf(c) + } + + resources := panos_terraforming.FilterCallableResources(t, options.Resources) + options.Resources = resources + + originalPathPattern := options.PathPattern + for _, v := range vsys { + provider := newPanosProvider() + log.Println(provider.GetName() + " importing VSYS " + v) + options.PathPattern = originalPathPattern + options.PathPattern = strings.ReplaceAll(options.PathPattern, "{provider}", "{provider}/"+v) + + err := Import(provider, options, []string{v}) + if err != nil { + return err + } + } + + return nil + }, + } + + cmd.AddCommand(listCmd(newPanosProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "firewall_device_config,firewall_networking,firewall_objects,firewall_policy", "") + cmd.PersistentFlags().StringSliceVarP(&vsys, "vsys", "", []string{}, "") + + return cmd +} + +func newPanosProvider() terraformutils.ProviderGenerator { + + return &panos_terraforming.PanosProvider{} +} diff --git a/cmd/provider_cmd_tencentcloud.go b/cmd/provider_cmd_tencentcloud.go new file mode 100644 index 000000000..21c0e7c1d --- /dev/null +++ b/cmd/provider_cmd_tencentcloud.go @@ -0,0 +1,53 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "log" + + tencentcloud_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/tencentcloud" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdTencentCloudImporter(options ImportOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "tencentcloud", + Short: "Import current state to Terraform configuration from Tencent Cloud", + Long: "Import current state to Terraform configuration from Tencent Cloud", + RunE: func(cmd *cobra.Command, args []string) error { + originalPathPattern := options.PathPattern + for _, region := range options.Regions { + provider := newTencentCloudProvider() + options.PathPattern = originalPathPattern + options.PathPattern += region + "/" + log.Println(provider.GetName() + " importing region " + region) + err := Import(provider, options, []string{region}) + if err != nil { + return err + } + } + return nil + }, + } + cmd.AddCommand(listCmd(newTencentCloudProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "cvm,vpc,cdn", "tencentcloud_vpc=id1:id2:id3") + cmd.PersistentFlags().StringSliceVarP(&options.Regions, "regions", "", []string{}, "ap-guangzhou") + return cmd +} + +func newTencentCloudProvider() terraformutils.ProviderGenerator { + return &tencentcloud_terraforming.TencentCloudProvider{} +} diff --git a/cmd/provider_cmd_vault.go b/cmd/provider_cmd_vault.go new file mode 100644 index 000000000..9b323b1ef --- /dev/null +++ b/cmd/provider_cmd_vault.go @@ -0,0 +1,48 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + vault_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/vault" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdVaultImporter(options ImportOptions) *cobra.Command { + var token, address string + cmd := &cobra.Command{ + Use: "vault", + Short: "Import current state to Terraform configuration from Vault", + Long: "Import current state to Terraform configuration from Vault", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newVaultProvider() + err := Import(provider, options, []string{address, token}) + if err != nil { + return err + } + return nil + }, + } + + cmd.AddCommand(listCmd(newVaultProvider())) + cmd.PersistentFlags().StringVarP(&address, "address", "a", "", "env param VAULT_ADDR") + cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "env param VAULT_TOKEN") + baseProviderFlags(cmd.PersistentFlags(), &options, "", "") + return cmd +} + +func newVaultProvider() terraformutils.ProviderGenerator { + return &vault_terraforming.Provider{} +} diff --git a/cmd/provider_cmd_xenorchestra.go b/cmd/provider_cmd_xenorchestra.go new file mode 100644 index 000000000..b38c90ab6 --- /dev/null +++ b/cmd/provider_cmd_xenorchestra.go @@ -0,0 +1,44 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + xenorchestra_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/xenorchestra" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdXenorchestraImporter(options ImportOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "xenorchestra", + Short: "Import current state to Terraform configuration from Xen Orchestra", + Long: "Import current state to Terraform configuration from Xen Orchestra", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newXenorchestraProvider() + err := Import(provider, options, []string{}) + if err != nil { + return err + } + return nil + }, + } + + cmd.AddCommand(listCmd(newXenorchestraProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "instance", "acl=name1:name2:name3") + return cmd +} + +func newXenorchestraProvider() terraformutils.ProviderGenerator { + return &xenorchestra_terraforming.XenorchestraProvider{} +} diff --git a/cmd/root.go b/cmd/root.go index 97d65adbc..c729f5c73 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -43,13 +43,14 @@ func providerImporterSubcommands() []func(options ImportOptions) *cobra.Command newCmdAwsImporter, newCmdAzureImporter, newCmdAliCloudImporter, + newCmdIbmImporter, // Cloud newCmdDigitalOceanImporter, - newCmdFastlyImporter, + newCmdEquinixMetalImporter, newCmdHerokuImporter, newCmdLinodeImporter, - newCmdNs1Importer, newCmdOpenStackImporter, + newCmdTencentCloudImporter, newCmdVultrImporter, newCmdYandexImporter, // Infrastructure Software @@ -58,17 +59,29 @@ func providerImporterSubcommands() []func(options ImportOptions) *cobra.Command newCmdRabbitMQImporter, // Network newCmdCloudflareImporter, + newCmdFastlyImporter, + newCmdNs1Importer, + newCmdPanosImporter, // VCS + newCmdAzureDevOpsImporter, newCmdGithubImporter, + newCmdGitLabImporter, // Monitoring & System Management newCmdDatadogImporter, newCmdNewRelicImporter, + newCmdMackerelImporter, + newCmdGrafanaImporter, + newCmdPagerDutyImporter, + newCmdOpsgenieImporter, // Community newCmdKeycloakImporter, newCmdLogzioImporter, newCmdCommercetoolsImporter, newCmdMikrotikImporter, + newCmdXenorchestraImporter, newCmdGmailfilterImporter, + newCmdVaultImporter, + newCmdOktaImporter, } } @@ -80,13 +93,16 @@ func providerGenerators() map[string]func() terraformutils.ProviderGenerator { newAWSProvider, newAzureProvider, newAliCloudProvider, + newIbmProvider, // Cloud newDigitalOceanProvider, + newEquinixMetalProvider, newFastlyProvider, newHerokuProvider, newLinodeProvider, newNs1Provider, newOpenStackProvider, + newTencentCloudProvider, newVultrProvider, // Infrastructure Software newKubernetesProvider, @@ -95,16 +111,22 @@ func providerGenerators() map[string]func() terraformutils.ProviderGenerator { // Network newCloudflareProvider, // VCS + newAzureDevOpsProvider, newGitHubProvider, + newGitLabProvider, // Monitoring & System Management newDataDogProvider, newNewRelicProvider, + newPagerDutyProvider, // Community newKeycloakProvider, newLogzioProvider, newCommercetoolsProvider, newMikrotikProvider, + newXenorchestraProvider, newGmailfilterProvider, + newVaultProvider, + newOktaProvider, } { list[providerGen().GetName()] = providerGen } diff --git a/cmd/version.go b/cmd/version.go index 1cc085752..93ac2c474 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/cobra" ) -const version = "v0.8.10" +const version = "v0.8.18" var versionCmd = &cobra.Command{ Use: "version", diff --git a/docs/alicloud.md b/docs/alicloud.md new file mode 100644 index 000000000..bc5883877 --- /dev/null +++ b/docs/alicloud.md @@ -0,0 +1,44 @@ + +### Use with AliCloud + +You can either edit your alicloud config directly, (usually it is `~/.aliyun/config.json`) +or run `aliyun configure` and enter the credentials when prompted. + +Terraformer will pick up the profile name specified in the `--profile` parameter. +It defaults to the first config in the config array. + +```sh +terraformer import alicloud --resources=ecs --regions=ap-southeast-3 --profile=default +``` + +List of supported AliCloud resources: + +* `dns` + * `alicloud_dns` + * `alicloud_dns_record` +* `ecs` + * `alicloud_instance` +* `keypair` + * `alicloud_key_pair` +* `nat` + * `alicloud_nat_gateway` +* `pvtz` + * `alicloud_pvtz_zone` + * `alicloud_pvtz_zone_attachment` + * `alicloud_pvtz_zone_record` +* `ram` + * `alicloud_ram_role` + * `alicloud_ram_role_policy_attachment` +* `rds` + * `alicloud_db_instance` +* `sg` + * `alicloud_security_group` + * `alicloud_security_group_rule` +* `slb` + * `alicloud_slb` + * `alicloud_slb_server_group` + * `alicloud_slb_listener` +* `vpc` + * `alicloud_vpc` +* `vswitch` + * `alicloud_vswitch` diff --git a/docs/aws.md b/docs/aws.md new file mode 100644 index 000000000..ffc966d80 --- /dev/null +++ b/docs/aws.md @@ -0,0 +1,360 @@ + +### Use with AWS + +Example: + +``` + terraformer import aws --resources=vpc,subnet --connect=true --regions=eu-west-1 --profile=prod + terraformer import aws --resources=vpc,subnet --filter=vpc=vpc_id1:vpc_id2:vpc_id3 --regions=eu-west-1 +``` + +#### Profiles support + +AWS configuration including environmental variables, shared credentials file (\~/.aws/credentials), and shared config file (\~/.aws/config) will be loaded by the tool by default. To use a specific profile, you can use the following command: + +``` +terraformer import aws --resources=vpc,subnet --regions=eu-west-1 --profile=prod +``` + +You can also provide no regions when importing resources: +``` +terraformer import aws --resources=cloudfront --profile=prod +``` +In that case terraformer will not know with which region resources are associated with and will not assume any region. That scenario is useful in case of global resources (e.g. CloudFront distributions or Route 53 records) and when region is passed implicitly through environmental variables or metadata service. + +#### Supported services + +* `accessanalyzer` + * `aws_accessanalyzer_analyzer` +* `acm` + * `aws_acm_certificate` +* `alb` (supports ALB and NLB) + * `aws_lb` + * `aws_lb_listener` + * `aws_lb_listener_rule` + * `aws_lb_listener_certificate` + * `aws_lb_target_group` + * `aws_lb_target_group_attachment` +* `api_gateway` + * `aws_api_gateway_authorizer` + * `aws_api_gateway_documentation_part` + * `aws_api_gateway_gateway_response` + * `aws_api_gateway_integration` + * `aws_api_gateway_integration_response` + * `aws_api_gateway_method` + * `aws_api_gateway_method_response` + * `aws_api_gateway_model` + * `aws_api_gateway_resource` + * `aws_api_gateway_rest_api` + * `aws_api_gateway_stage` + * `aws_api_gateway_usage_plan` + * `aws_api_gateway_vpc_link` +* `appsync` + * `aws_appsync_graphql_api` +* `auto_scaling` + * `aws_autoscaling_group` + * `aws_launch_configuration` + * `aws_launch_template` +* `batch` + * `aws_batch_compute_environment` + * `aws_batch_job_definition` + * `aws_batch_job_queue` +* `budgets` + * `aws_budgets_budget` +* `cloud9` + * `aws_cloud9_environment_ec2` +* `cloudformation` + * `aws_cloudformation_stack` + * `aws_cloudformation_stack_set` + * `aws_cloudformation_stack_set_instance` +* `cloudfront` + * `aws_cloudfront_distribution` +* `cloudhsm` + * `aws_cloudhsm_v2_cluster` + * `aws_cloudhsm_v2_hsm` +* `cloudtrail` + * `aws_cloudtrail` +* `cloudwatch` + * `aws_cloudwatch_dashboard` + * `aws_cloudwatch_event_rule` + * `aws_cloudwatch_event_target` + * `aws_cloudwatch_metric_alarm` +* `codebuild` + * `aws_codebuild_project` +* `codecommit` + * `aws_codecommit_repository` +* `codedeploy` + * `aws_codedeploy_app` +* `codepipeline` + * `aws_codepipeline` + * `aws_codepipeline_webhook` +* `cognito` + * `aws_cognito_identity_pool` + * `aws_cognito_user_pool` +* `config` + * `aws_config_config_rule` + * `aws_config_configuration_recorder` + * `aws_config_delivery_channel` +* `customer_gateway` + * `aws_customer_gateway` +* `datapipeline` + * `aws_datapipeline_pipeline` +* `devicefarm` + * `aws_devicefarm_project` +* `docdb` + * `aws_docdb_cluster` + * `aws_docdb_cluster_instance` + * `aws_docdb_cluster_parameter_group` + * `aws_docdb_subnet_group` +* `dynamodb` + * `aws_dynamodb_table` +* `ebs` + * `aws_ebs_volume` + * `aws_volume_attachment` +* `ec2_instance` + * `aws_instance` +* `ecr` + * `aws_ecr_lifecycle_policy` + * `aws_ecr_repository` + * `aws_ecr_repository_policy` +* `ecrpublic` + * `aws_ecrpublic_repository` +* `ecs` + * `aws_ecs_cluster` + * `aws_ecs_service` + * `aws_ecs_task_definition` +* `efs` + * `aws_efs_access_point` + * `aws_efs_file_system` + * `aws_efs_file_system_policy` + * `aws_efs_mount_target` +* `eip` + * `aws_eip` +* `eks` + * `aws_eks_cluster` +* `elasticache` + * `aws_elasticache_cluster` + * `aws_elasticache_parameter_group` + * `aws_elasticache_subnet_group` + * `aws_elasticache_replication_group` +* `elastic_beanstalk` + * `aws_elastic_beanstalk_application` + * `aws_elastic_beanstalk_environment` +* `elb` + * `aws_elb` +* `emr` + * `aws_emr_cluster` + * `aws_emr_security_configuration` +* `eni` + * `aws_network_interface` +* `es` + * `aws_elasticsearch_domain` +* `firehose` + * `aws_kinesis_firehose_delivery_stream` +* `glue` + * `glue_crawler` + * `aws_glue_catalog_database` + * `aws_glue_catalog_table` + * `aws_glue_job` + * `aws_glue_trigger` +* `iam` + * `aws_iam_group` + * `aws_iam_group_policy` + * `aws_iam_group_policy_attachment` + * `aws_iam_instance_profile` + * `aws_iam_policy` + * `aws_iam_role` + * `aws_iam_role_policy` + * `aws_iam_role_policy_attachment` + * `aws_iam_user` + * `aws_iam_user_group_membership` + * `aws_iam_user_policy` + * `aws_iam_user_policy_attachment` +* `igw` + * `aws_internet_gateway` +* `iot` + * `aws_iot_thing` + * `aws_iot_thing_type` + * `aws_iot_topic_rule` + * `aws_iot_role_alias` +* `kinesis` + * `aws_kinesis_stream` +* `kms` + * `aws_kms_key` + * `aws_kms_alias` + * `aws_kms_grant` +* `lambda` + * `aws_lambda_event_source_mapping` + * `aws_lambda_function` + * `aws_lambda_function_event_invoke_config` + * `aws_lambda_layer_version` +* `logs` + * `aws_cloudwatch_log_group` +* `media_package` + * `aws_media_package_channel` +* `media_store` + * `aws_media_store_container` +* `msk` + * `aws_msk_cluster` +* `nacl` + * `aws_network_acl` +* `nat` + * `aws_nat_gateway` +* `opsworks` + * `aws_opsworks_application` + * `aws_opsworks_custom_layer` + * `aws_opsworks_instance` + * `aws_opsworks_java_app_layer` + * `aws_opsworks_php_app_layer` + * `aws_opsworks_rds_db_instance` + * `aws_opsworks_stack` + * `aws_opsworks_static_web_layer` + * `aws_opsworks_user_profile` +* `organization` + * `aws_organizations_account` + * `aws_organizations_organization` + * `aws_organizations_organizational_unit` + * `aws_organizations_policy` + * `aws_organizations_policy_attachment` +* `qldb` + * `aws_qldb_ledger` +* `rds` + * `aws_db_instance` + * `aws_db_proxy` + * `aws_db_cluster` + * `aws_db_parameter_group` + * `aws_db_subnet_group` + * `aws_db_option_group` + * `aws_db_event_subscription` +* `resourcegroups` + * `aws_resourcegroups_group` +* `route53` + * `aws_route53_zone` + * `aws_route53_record` +* `route_table` + * `aws_route_table` + * `aws_main_route_table_association` + * `aws_route_table_association` +* `s3` + * `aws_s3_bucket` +* `secretsmanager` + * `aws_secretsmanager_secret` +* `securityhub` + * `aws_securityhub_account` + * `aws_securityhub_member` + * `aws_securityhub_standards_subscription` +* `servicecatalog` + * `aws_servicecatalog_portfolio` +* `ses` + * `aws_ses_configuration_set` + * `aws_ses_domain_identity` + * `aws_ses_email_identity` + * `aws_ses_receipt_rule` + * `aws_ses_receipt_rule_set` + * `aws_ses_template` +* `sfn` + * `aws_sfn_activity` + * `aws_sfn_state_machine` +* `sg` + * `aws_security_group` + * `aws_security_group_rule` (if a rule cannot be inlined) +* `sns` + * `aws_sns_topic` + * `aws_sns_topic_subscription` +* `sqs` + * `aws_sqs_queue` +* `ssm` + * `aws_ssm_parameter` +* `subnet` + * `aws_subnet` +* `swf` + * `aws_swf_domain` +* `transit_gateway` + * `aws_ec2_transit_gateway_route_table` + * `aws_ec2_transit_gateway_vpc_attachment` +* `waf` + * `aws_waf_byte_match_set` + * `aws_waf_geo_match_set` + * `aws_waf_ipset` + * `aws_waf_rate_based_rule` + * `aws_waf_regex_match_set` + * `aws_waf_regex_pattern_set` + * `aws_waf_rule` + * `aws_waf_rule_group` + * `aws_waf_size_constraint_set` + * `aws_waf_sql_injection_match_set` + * `aws_waf_web_acl` + * `aws_waf_xss_match_set` +* `waf_regional` + * `aws_wafregional_byte_match_set` + * `aws_wafregional_geo_match_set` + * `aws_wafregional_ipset` + * `aws_wafregional_rate_based_rule` + * `aws_wafregional_regex_match_set` + * `aws_wafregional_regex_pattern_set` + * `aws_wafregional_rule` + * `aws_wafregional_rule_group` + * `aws_wafregional_size_constraint_set` + * `aws_wafregional_sql_injection_match_set` + * `aws_wafregional_web_acl` + * `aws_wafregional_xss_match_set` +* `vpc` + * `aws_vpc` +* `vpc_peering` + * `aws_vpc_peering_connection` +* `vpn_connection` + * `aws_vpn_connection` +* `vpn_gateway` + * `aws_vpn_gateway` +* `workspaces` + * `aws_workspaces_directory` + * `aws_workspaces_ip_group` + * `aws_workspaces_workspace` +* `xray` + * `aws_xray_sampling_rule` + +#### Global services + +AWS services that are global will be imported without specified region even if several regions will be passed. It is to ensure only one representation of an AWS resource is imported. + +List of global AWS services: +* `budgets` +* `cloudfront` +* `ecrpublic` +* `iam` +* `organization` +* `route53` +* `waf` + +#### Attribute filters + +Attribute filters allow filtering across different resource types by its attributes. + +``` +terraformer import aws --resources=ec2_instance,ebs --filter="Name=tags.costCenter;Value=20000:'20001:1'" --regions=eu-west-1 +``` +Will only import AWS EC2 instances along with EBS volumes annotated with tag `costCenter` with values `20000` or `20001:1`. Attribute filters are by default applicable to all resource types although it's possible to specify to what resource type a given filter should be applicable to by providing `Type=` parameter. For example: +``` +terraformer import aws --resources=ec2_instance,ebs --filter=Type=ec2_instance;Name=tags.costCenter;Value=20000:'20001:1' --regions=eu-west-1 +``` +Will work as same as example above with a change the filter will be applicable only to `ec2_instance` resources. + +Few more examples - How to import ec2 instance based on instance name and id +``` +terraformer import aws --resources=ec2_instance --filter="Name=tags.Name;Value=Terraformer" --regions=us-east-1 +``` +This command imports ec2 instance having name as Terraformer. +``` +terraformer import aws --resources=ec2_instance --filter="Name=id;Value=i-0xxxxxxxxx" --regions=us-east-1 +``` +This command imports ec2 instance having insatnce-id as i-0xxxxxxxxx. + +Due to fact API Gateway generates a lot of resources, it's possible to issue a filtering query to retrieve resources related to a given REST API by tags. To fetch resources related to a REST API resource with a tag `STAGE` and value `dev`, add parameter `--filter="Type=api_gateway_rest_api;Name=tags.STAGE;Value=dev"`. + +#### SQS queues retrieval + +Terraformer uses AWS [ListQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ListQueues.html) API call to fetch available queues. The API is able to return only up to 1000 queues and an additional name prefix should be passed to filter the list results. It's possible to pass `QueueNamePrefix` parameter by environmental variable `SQS_PREFIX`. + +#### Security groups and rules + +Terraformer by default will try to keep rules in security groups as long as no circular dependencies are detected. This approach is implemented to keep the rules as tidy as possible but there can be cases when this behaviour is not desirable (see [GoogleCloudPlatform/terraformer#493](https://github.com/GoogleCloudPlatform/terraformer/issues/493)). To make Terraformer split rules from security groups, add `SPLIT_SG_RULES` environmental variable with any value. diff --git a/docs/azure.md b/docs/azure.md new file mode 100644 index 000000000..8192a71e4 --- /dev/null +++ b/docs/azure.md @@ -0,0 +1,206 @@ +# Use with Azure + +Supports [Azure CLI](https://www.terraform.io/docs/providers/azurerm/guides/azure_cli.html), [Service Principal with Client Certificate](https://www.terraform.io/docs/providers/azurerm/guides/service_principal_client_certificate.html), and [Service Principal with Client Secret](https://www.terraform.io/docs/providers/azurerm/guides/service_principal_client_secret.html). + +## Example + +``` sh +# Using Azure CLI (az login) +export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] + +# Using Service Principal with Client Certificate +export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] +export ARM_CLIENT_ID=[CLIENT_ID] +export ARM_CLIENT_CERTIFICATE_PATH="/path/to/my/client/certificate.pfx" +export ARM_CLIENT_CERTIFICATE_PASSWORD=[CLIENT_CERTIFICATE_PASSWORD] +export ARM_TENANT_ID=[TENANT_ID] + +# Service Principal with Client Secret +export ARM_SUBSCRIPTION_ID=[SUBSCRIPTION_ID] +export ARM_CLIENT_ID=[CLIENT_ID] +export ARM_CLIENT_SECRET=[CLIENT_SECRET] +export ARM_TENANT_ID=[TENANT_ID] + +./terraformer import azure -r resource_group +./terraformer import azure -R my_resource_group -r virtual_network,resource_group +./terraformer import azure -r resource_group --filter=resource_group=/subscriptions//resourceGroups/ +``` + + +## List of supported Azure resources + +* `analysis` + * `azurerm_analysis_services_server` +* `app_service` + * `azurerm_app_service` +* `application_gateway` + * `azurerm_application_gateway` +* `container` + * `azurerm_container_group` + * `azurerm_container_registry` + * `azurerm_container_registry_webhook` +* `cosmosdb` + * `azurerm_cosmosdb_account` + * `azurerm_cosmosdb_sql_container` + * `azurerm_cosmosdb_sql_database` + * `azurerm_cosmosdb_table` +* `database` + * `azurerm_mariadb_configuration` + * `azurerm_mariadb_database` + * `azurerm_mariadb_firewall_rule` + * `azurerm_mariadb_server` + * `azurerm_mariadb_virtual_network_rule` + * `azurerm_mysql_configuration` + * `azurerm_mysql_database` + * `azurerm_mysql_firewall_rule` + * `azurerm_mysql_server` + * `azurerm_mysql_virtual_network_rule` + * `azurerm_postgresql_configuration` + * `azurerm_postgresql_database` + * `azurerm_postgresql_firewall_rule` + * `azurerm_postgresql_server` + * `azurerm_postgresql_virtual_network_rule` + * `azurerm_sql_database` + * `azurerm_sql_active_directory_administrator` + * `azurerm_sql_elasticpool` + * `azurerm_sql_failover_group` + * `azurerm_sql_firewall_rule` + * `azurerm_sql_server` + * `azurerm_sql_virtual_network_rule` +* `databricks` + * `azurerm_databricks_workspace` +* `data_factory` + * `azurerm_data_factory` + * `azurerm_data_factory_pipeline` + * `azurerm_data_factory_data_flow` + * `azurerm_data_factory_dataset_azure_blob` + * `azurerm_data_factory_dataset_binary` + * `azurerm_data_factory_dataset_cosmosdb_sqlapi` + * `azurerm_data_factory_custom_dataset` + * `azurerm_data_factory_dataset_delimited_text` + * `azurerm_data_factory_dataset_http` + * `azurerm_data_factory_dataset_json` + * `azurerm_data_factory_dataset_mysql` + * `azurerm_data_factory_dataset_parquet` + * `azurerm_data_factory_dataset_postgresql` + * `azurerm_data_factory_dataset_snowflake` + * `azurerm_data_factory_dataset_sql_server_table` + * `azurerm_data_factory_integration_runtime_azure` + * `azurerm_data_factory_integration_runtime_managed` + * `azurerm_data_factory_integration_runtime_azure_ssis` + * `azurerm_data_factory_integration_runtime_self_hosted` + * `azurerm_data_factory_linked_service_azure_blob_storage` + * `azurerm_data_factory_linked_service_azure_databricks` + * `azurerm_data_factory_linked_service_azure_file_storage` + * `azurerm_data_factory_linked_service_azure_function` + * `azurerm_data_factory_linked_service_azure_search` + * `azurerm_data_factory_linked_service_azure_sql_database` + * `azurerm_data_factory_linked_service_azure_table_storage` + * `azurerm_data_factory_linked_service_cosmosdb` + * `azurerm_data_factory_linked_custom_service` + * `azurerm_data_factory_linked_service_data_lake_storage_gen2` + * `azurerm_data_factory_linked_service_key_vault` + * `azurerm_data_factory_linked_service_kusto` + * `azurerm_data_factory_linked_service_mysql` + * `azurerm_data_factory_linked_service_odata` + * `azurerm_data_factory_linked_service_postgresql` + * `azurerm_data_factory_linked_service_sftp` + * `azurerm_data_factory_linked_service_snowflake` + * `azurerm_data_factory_linked_service_sql_server` + * `azurerm_data_factory_linked_service_synapse` + * `azurerm_data_factory_linked_service_web` + * `azurerm_data_factory_trigger_blob_event` + * `azurerm_data_factory_trigger_schedule` + * `azurerm_data_factory_trigger_tumbling_window` +* `disk` + * `azurerm_managed_disk` +* `dns` + * `azurerm_dns_a_record` + * `azurerm_dns_aaaa_record` + * `azurerm_dns_caa_record` + * `azurerm_dns_cname_record` + * `azurerm_dns_mx_record` + * `azurerm_dns_ns_record` + * `azurerm_dns_ptr_record` + * `azurerm_dns_srv_record` + * `azurerm_dns_txt_record` + * `azurerm_dns_zone` +* `load_balancer` + * `azurerm_lb` + * `azurerm_lb_backend_address_pool` + * `azurerm_lb_nat_rule` + * `azurerm_lb_probe` +* `eventhub` + * `azurerm_eventhub_namespace` + * `azurerm_eventhub` + * `azurerm_eventhub_consumer_group` + * `azurerm_eventhub_namespace_authorization_rule` +* `network_interface` + * `azurerm_network_interface` +* `network_security_group` + * `azurerm_network_security_group` + * `azurerm_network_security_rule` +* `network_watcher` + * `azurerm_network_watcher` + * `azurerm_network_watcher_flow_log` + * `azurerm_network_packet_capture` +* `private_dns` + * `azurerm_private_dns_a_record` + * `azurerm_private_dns_aaaa_record` + * `azurerm_private_dns_cname_record` + * `azurerm_private_dns_mx_record` + * `azurerm_private_dns_ptr_record` + * `azurerm_private_dns_srv_record` + * `azurerm_private_dns_txt_record` + * `azurerm_private_dns_zone` + * `azurerm_private_dns_zone_virtual_network_link` +* `private_endpoint` + * `azurerm_private_endpoint` + * `azurerm_private_link_service` +* `public_ip` + * `azurerm_public_ip` + * `azurerm_public_ip_prefix` +* `redis` + * `azurerm_redis_cache` +* `purview` + * `azurerm_purview_account` +* `resource_group` + * `azurerm_resource_group` + * `azurerm_management_lock` +* `route_table` + * `azurerm_route_table` + * `azurerm_route` + * `azurerm_route_filter` +* `scaleset` + * `azurerm_virtual_machine_scale_set` +* `security_center` + * `azurerm_security_center_contact` + * `azurerm_security_center_subscription_pricing` +* `storage_account` + * `azurerm_storage_account` + * `azurerm_storage_blob` + * `azurerm_storage_container` +* `synapse` + * `azurerm_synapse_workspace` + * `azurerm_synapse_sql_pool` + * `azurerm_synapse_spark_pool` + * `azurerm_synapse_firewall_rule` + * `azurerm_synapse_managed_private_endpoint` + * `azurerm_synapse_private_link_hub` +* `virtual_machine` + * `azurerm_ssh_public_key` + * `azurerm_virtual_machine` +* `virtual_network` + * `azurerm_virtual_network` +* `subnet` + * `azurerm_subnet` + * `azurerm_subnet_service_endpoint_storage_policy` + * `azurerm_subnet_nat_gateway_association` + * `azurerm_subnet_route_table_association` + * `azurerm_subnet_network_security_group_association` + +## Notes + +### Virtual networks and subnets + +Terraformer will import `azurerm_virtual_network` config with inlined subnet information swipped, in order to avoid any potential circular dependencies. To import the subnet information, please also import `azurerm_subnet`. diff --git a/docs/azuredevops.md b/docs/azuredevops.md new file mode 100644 index 000000000..2031c2472 --- /dev/null +++ b/docs/azuredevops.md @@ -0,0 +1,26 @@ +# Use with Azure DevOps + +Supports acess via [Personal Access Token](https://registry.terraform.io/providers/microsoft/azuredevops/latest/docs/guides/authenticating_using_the_personal_access_token). + +## Example + +``` sh +export AZDO_ORG_SERVICE_URL="https://dev.azure.com/" +export AZDO_PERSONAL_ACCESS_TOKEN="" + +./terraformer import azuredevops -r * +./terraformer import azuredevops -r project,git_repository +``` + +## List of supported Azure resources + +* `project` + * `azuredevops_project` +* `group` + * `azuredevops_group` +* `git_repository` + * `azuredevops_git_repository` + +## Notes + +Since [Terraform Provider for Azure DevOps](https://github.com/microsoft/terraform-provider-azuredevops) `version 0.17`. diff --git a/docs/cloudflare.md b/docs/cloudflare.md new file mode 100644 index 000000000..471591576 --- /dev/null +++ b/docs/cloudflare.md @@ -0,0 +1,35 @@ +### Use with Cloudflare + +Example using a Cloudflare API Key and corresponding email: +``` +export CLOUDFLARE_API_KEY=[CLOUDFLARE_API_KEY] +export CLOUDFLARE_EMAIL=[CLOUDFLARE_EMAIL] +export CLOUDFLARE_ACCOUNT_ID=[CLOUDFLARE_ACCOUNT_ID] + ./terraformer import cloudflare --resources=firewall,dns +``` + +or using a Cloudflare API Token: + +``` +export CLOUDFLARE_API_TOKEN=[CLOUDFLARE_API_TOKEN] +export CLOUDFLARE_ACCOUNT_ID=[CLOUDFLARE_ACCOUNT_ID] + ./terraformer import cloudflare --resources=firewall,dns +``` + +List of supported Cloudflare services: + +* `access` + * `cloudflare_access_application` +* `dns` + * `cloudflare_zone` + * `cloudflare_record` +* `firewall` + * `cloudflare_access_rule` + * `cloudflare_filter` + * `cloudflare_firewall_rule` + * `cloudflare_zone_lockdown` + * `cloudflare_rate_limit` +* `page_rule` + * `cloudflare_page_rule` +* `account_member` + * `cloudflare_account_member` diff --git a/docs/commercetools.md b/docs/commercetools.md new file mode 100644 index 000000000..eebdea5eb --- /dev/null +++ b/docs/commercetools.md @@ -0,0 +1,53 @@ +### Use with [Commercetools](https://commercetools.com/de/) + +This provider use the [terraform-provider-commercetools](https://github.com/labd/terraform-provider-commercetools). The terraformer provider was build by [Dustin Deus](https://github.com/StarpTech). + +Example: + +Export required variables: + +```bash +export CTP_PROJECT_KEY=key +export CTP_CLIENT_ID=foo +export CTP_CLIENT_SECRET=bar +export CTP_CLIENT_SCOPE=scope +``` + +Export optional variables in case default values are not appropriate: + +```bash +export CTP_BASE_URL=base_url # default: https://api.sphere.io +export CTP_TOKEN_URL=token_url # default: https://auth.sphere.io +``` + +Run terraformer + +```bash +./terraformer plan commercetools -r=types # Only planning +./terraformer import commercetools -r=types # Import commercetools types +``` + +List of supported [commercetools](https://commercetools.com/de/) resources: + +- `api_extension` + - `commercetools_api_extension` +- `channel` + - `commercetools_channel` +- `custom_object` + - `commercetools_custom_object` +- `product_type` + - `commercetools_product_type` +- `shipping_method` + - `commercetools_shipping_method` +- `shipping_zone` + - `commercetools_shipping_zone` +- `state` + - `commercetools_state` +- `store` + - `commercetools_store` +- `subscription` + - `commercetools_subscription` +- `tax_category` + - `commercetools_tax_category` +- `types` + - `commercetools_type` diff --git a/docs/datadog.md b/docs/datadog.md new file mode 100644 index 000000000..f34eadbec --- /dev/null +++ b/docs/datadog.md @@ -0,0 +1,80 @@ +### Use with Datadog + +Example: + +``` + ./terraformer import datadog --resources=monitor --api-key=YOUR_DATADOG_API_KEY // or DATADOG_API_KEY in env --app-key=YOUR_DATADOG_APP_KEY // or DATADOG_APP_KEY in env --api-url=DATADOG_API_URL // or DATADOG_HOST in env --validate=VALIDATE_BOOL // or DATADOG_VALIDATE in env + ./terraformer import datadog --resources=monitor --filter=monitor=id1:id2:id4 --api-key=YOUR_DATADOG_API_KEY // or DATADOG_API_KEY in env --app-key=YOUR_DATADOG_APP_KEY // or DATADOG_APP_KEY in env --validate=VALIDATE_BOOL // or DATADOG_VALIDATE in env +``` + +List of supported Datadog services: + +* `dashboard` + * `datadog_dashboard` +* `dashboard_json` + * `datadog_dashboard_json` +* `dashboard_list` + * `datadog_dashboard_list` +* `downtime` + * `datadog_downtime` +* `logs_archive` + * `datadog_logs_archive` +* `logs_archive_order` + * `datadog_logs_archive_order` +* `logs_custom_pipeline` + * `datadog_logs_custom_pipeline` +* `logs_integration_pipeline` + * `datadog_logs_integration_pipeline` +* `logs_pipeline_order` + * `datadog_logs_pipeline_order` +* `logs_index` + * `datadog_logs_index` +* `logs_index_order` + * `datadog_logs_index_order` +* `integration_aws` + * `datadog_integration_aws` +* `integration_aws_lambda_arn` + * `datadog_integration_aws_lambda_arn` +* `integration_aws_log_collection` + * `datadog_integration_aws_log_collection` +* `integration_azure` + * `datadog_integration_azure` + * **_NOTE:_** Sensitive field `client_secret` is not generated and needs to be manually set +* `integration_gcp` + * `datadog_integration_gcp` + * **_NOTE:_** Sensitive fields `private_key, private_key_id, client_id` is not generated and needs to be manually set +* `integration_pagerduty` + * `datadog_integration_pagerduty` +* `integration_pagerduty_service_object` + * `datadog_integration_pagerduty_service_object` +* `integration_slack_channel` + * `datadog_integration_slack_channel` + * **_NOTE:_** Importing resource requires resource ID or `account_name` to be passed via [Filter][1] option +* `metric_metadata` + * `datadog_metric_metadata` + * **_NOTE:_** Importing resource requires resource ID's to be passed via [Filter][1] option +* `monitor` + * `datadog_monitor` +* `role` + * `datadog_role` +* `screenboard` + * `datadog_screenboard` +* `security_monitoring_default_rule` + * `datadog_security_monitoring_default_rule` +* `security_monitoring_rule` + * `datadog_security_monitoring_rule` +* `service_level_objective` + * `datadog_service_level_objective` +* `synthetics_test` + * `datadog_synthetics_test` +* `synthetics_global_variables` + * `datadog_synthetics_global_variables` + * **_NOTE:_** Importing resource requires resource ID's to be passed via [Filter][1] option +* `synthetics_private_location` + * `datadog_synthetics_private_location` +* `timeboard` + * `datadog_timeboard` +* `user` + * `datadog_user` + +[1]: https://github.com/GoogleCloudPlatform/terraformer/blob/master/README.md#filtering \ No newline at end of file diff --git a/docs/digitalocean.md b/docs/digitalocean.md new file mode 100644 index 000000000..31af052f7 --- /dev/null +++ b/docs/digitalocean.md @@ -0,0 +1,47 @@ +### Use with DigitalOcean + +Example: + +``` +export DIGITALOCEAN_TOKEN=[DIGITALOCEAN_TOKEN] +./terraformer import digitalocean -r project,droplet +``` + +List of supported DigitalOcean resources: + +* `cdn` + * `digitalocean_cdn` +* `certificate` + * `digitalocean_certificate` +* `database_cluster` + * `digitalocean_database_cluster` + * `digitalocean_database_connection_pool` + * `digitalocean_database_db` + * `digitalocean_database_replica` + * `digitalocean_database_user` +* `domain` + * `digitalocean_domain` + * `digitalocean_record` +* `droplet` + * `digitalocean_droplet` +* `droplet_snapshot` + * `digitalocean_droplet_snapshot` +* `firewall` + * `digitalocean_firewall` +* `floating_ip` + * `digitalocean_floating_ip` +* `kubernetes_cluster` + * `digitalocean_kubernetes_cluster` + * `digitalocean_kubernetes_node_pool` +* `loadbalancer` + * `digitalocean_loadbalancer` +* `project` + * `digitalocean_project` +* `ssh_key` + * `digitalocean_ssh_key` +* `tag` + * `digitalocean_tag` +* `volume` + * `digitalocean_volume` +* `volume_snapshot` + * `digitalocean_volume_snapshot` diff --git a/docs/equinixmetal.md b/docs/equinixmetal.md new file mode 100644 index 000000000..202933653 --- /dev/null +++ b/docs/equinixmetal.md @@ -0,0 +1,20 @@ +### Use with Equinix Metal + +Example: + +``` +export METAL_AUTH_TOKEN=[METAL_AUTH_TOKEN] +export PACKET_PROJECT_ID=[PROJECT_ID] +./terraformer import metal -r volume,device +``` + +List of supported Equinix Metal resources: + +* `device` + * `metal_device` +* `volume` + * `metal_volume` +* `sshkey` + * `metal_ssh_key` +* `spotmarketrequest` + * `metal_spot_market_request` diff --git a/docs/fastly.md b/docs/fastly.md new file mode 100644 index 000000000..d18bfb0a9 --- /dev/null +++ b/docs/fastly.md @@ -0,0 +1,22 @@ +### Use with Fastly + +Example: + +``` +export FASTLY_API_KEY=[FASTLY_API_KEY] +export FASTLY_CUSTOMER_ID=[FASTLY_CUSTOMER_ID] +./terraformer import fastly -r service_v1,user +``` + +List of supported Fastly resources: + +* `service_v1` + * `fastly_service_acl_entries_v1` + * `fastly_service_compute` + * `fastly_service_dictionary_items_v1` + * `fastly_service_dynamic_snippet_content_v1` + * `fastly_service_v1` +* `user` + * `fastly_user_v1` +* `tls_subscription` + * `fastly_tls_subscription` diff --git a/docs/gcp.md b/docs/gcp.md new file mode 100644 index 000000000..125c8184d --- /dev/null +++ b/docs/gcp.md @@ -0,0 +1,173 @@ +### Use with GCP + +In order to access the information from your Google Project, you need to provide authentication credentials +by setting up the environment variable `GOOGLE_APPLICATION_CREDENTIALS` with the file path of the JSON +file that contains your service account key. + +[![asciicast](https://asciinema.org/a/243961.svg)](https://asciinema.org/a/243961) + +Example: + +``` +terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --connect=true --regions=europe-west1,europe-west4 --projects=aaa,fff +terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --filter=compute_firewall=rule1:rule2:rule3 --regions=europe-west1 --projects=aaa,fff +``` + +For google-beta provider: + +``` +terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --regions=europe-west4 --projects=aaa --provider-type beta +``` + +List of supported GCP services: + +* `addresses` + * `google_compute_address` +* `autoscalers` + * `google_compute_autoscaler` +* `backendBuckets` + * `google_compute_backend_bucket` +* `backendServices` + * `google_compute_backend_service` +* `bigQuery` + * `google_bigquery_dataset` + * `google_bigquery_table` +* `cloudFunctions` + * `google_cloudfunctions_function` +* `cloudsql` + * `google_sql_database_instance` + * `google_sql_database` +* `dataProc` + * `google_dataproc_cluster` +* `disks` + * `google_compute_disk` +* `externalVpnGateways` + * `google_compute_external_vpn_gateway` +* `dns` + * `google_dns_managed_zone` + * `google_dns_record_set` +* `firewall` + * `google_compute_firewall` +* `forwardingRules` + * `google_compute_forwarding_rule` +* `gcs` + * `google_storage_bucket` + * `google_storage_bucket_acl` + * `google_storage_default_object_acl` + * `google_storage_bucket_iam_binding` + * `google_storage_bucket_iam_member` + * `google_storage_bucket_iam_policy` + * `google_storage_notification` +* `gke` + * `google_container_cluster` + * `google_container_node_pool` +* `globalAddresses` + * `google_compute_global_address` +* `globalForwardingRules` + * `google_compute_global_forwarding_rule` +* `healthChecks` + * `google_compute_health_check` +* `httpHealthChecks` + * `google_compute_http_health_check` +* `httpsHealthChecks` + * `google_compute_https_health_check` +* `iam` + * `google_project_iam_custom_role` + * `google_project_iam_member` + * `google_service_account` +* `images` + * `google_compute_image` +* `instanceGroupManagers` + * `google_compute_instance_group_manager` +* `instanceGroups` + * `google_compute_instance_group` +* `instanceTemplates` + * `google_compute_instance_template` +* `instances` + * `google_compute_instance` +* `interconnectAttachments` + * `google_compute_interconnect_attachment` +* `kms` + * `google_kms_key_ring` + * `google_kms_crypto_key` +* `logging` + * `google_logging_metric` +* `memoryStore` + * `google_redis_instance` +* `monitoring` + * `google_monitoring_alert_policy` + * `google_monitoring_group` + * `google_monitoring_notification_channel` + * `google_monitoring_uptime_check_config` +* `networks` + * `google_compute_network` +* `packetMirrorings` + * `google_compute_packet_mirroring` +* `nodeGroups` + * `google_compute_node_group` +* `nodeTemplates` + * `google_compute_node_template` +* `project` + * `google_project` +* `pubsub` + * `google_pubsub_subscription` + * `google_pubsub_topic` +* `regionAutoscalers` + * `google_compute_region_autoscaler` +* `regionBackendServices` + * `google_compute_region_backend_service` +* `regionDisks` + * `google_compute_region_disk` +* `regionHealthChecks` + * `google_compute_region_health_check` +* `regionInstanceGroups` + * `google_compute_region_instance_group` +* `regionSslCertificates` + * `google_compute_region_ssl_certificate` +* `regionTargetHttpProxies` + * `google_compute_region_target_http_proxy` +* `regionTargetHttpsProxies` + * `google_compute_region_target_https_proxy` +* `regionUrlMaps` + * `google_compute_region_url_map` +* `reservations` + * `google_compute_reservation` +* `resourcePolicies` + * `google_compute_resource_policy` +* `regionInstanceGroupManagers` + * `google_compute_region_instance_group_manager` +* `routers` + * `google_compute_router` +* `routes` + * `google_compute_route` +* `schedulerJobs` + * `google_cloud_scheduler_job` +* `securityPolicies` + * `google_compute_security_policy` +* `sslCertificates` + * `google_compute_managed_ssl_certificate` +* `sslPolicies` + * `google_compute_ssl_policy` +* `subnetworks` + * `google_compute_subnetwork` +* `targetHttpProxies` + * `google_compute_target_http_proxy` +* `targetHttpsProxies` + * `google_compute_target_https_proxy` +* `targetInstances` + * `google_compute_target_instance` +* `targetPools` + * `google_compute_target_pool` +* `targetSslProxies` + * `google_compute_target_ssl_proxy` +* `targetTcpProxies` + * `google_compute_target_tcp_proxy` +* `targetVpnGateways` + * `google_compute_vpn_gateway` +* `urlMaps` + * `google_compute_url_map` +* `vpnTunnels` + * `google_compute_vpn_tunnel` + +Your `tf` and `tfstate` files are written by default to +`generated/gcp/zone/service`. diff --git a/docs/github.md b/docs/github.md new file mode 100644 index 000000000..40e25bde9 --- /dev/null +++ b/docs/github.md @@ -0,0 +1,37 @@ +### Use with GitHub + +Example: + +``` + ./terraformer import github --owner=YOUR_ORGANIZATION --resources=repositories --token=YOUR_TOKEN // or GITHUB_TOKEN in env + ./terraformer import github --owner=YOUR_ORGANIZATION --resources=repositories --filter=repository=id1:id2:id4 --token=YOUR_TOKEN // or GITHUB_TOKEN in env + + ./terraformer import github --owner=YOUR_ORGANIZATION --resources=repositories --base-url=https://your-enterprise-github-url +``` + +Supports only organizational resources. List of supported resources: + +* `members` + * `github_membership` +* `organization_blocks` + * `github_organization_block` +* `organization_projects` + * `github_organization_project` +* `organization_webhooks` + * `github_organization_webhook` +* `repositories` + * `github_repository` + * `github_repository_webhook` + * `github_branch_protection` + * `github_repository_collaborator` + * `github_repository_deploy_key` +* `teams` + * `github_team` + * `github_team_membership` + * `github_team_repository` +* `user_ssh_keys` + * `github_user_ssh_key` + +Notes: +* Terraformer can't get webhook secrets from the GitHub API. If you use a secret token in any of your webhooks, running `terraform plan` will result in a change being detected: +=> `configuration.#: "1" => "0"` in tfstate only. diff --git a/docs/gitlab.md b/docs/gitlab.md new file mode 100644 index 000000000..fabbe4ab4 --- /dev/null +++ b/docs/gitlab.md @@ -0,0 +1,20 @@ +### Use with GitLab + +Example: + +```shell +./terraformer import gitlab --group=GROUP_TO_IMPORT --resources=projects --token=YOUR_TOKEN # or GITLAB_TOKEN in env +./terraformer import gitlab --group=GROUP_TO_IMPORT --resources=groups --base-url=https://your-self-hosted-gitlab-domain/api/v4 +``` + +List of supported resources: + +* `projects` + * `gitlab_project` + * `gitlab_project_value` + * `gitlab_project_membership` + * `gitlab_tag_protection` + * `gitlab_branch_protection` +* `groups` + * `gitlab_group_membership` + * `gitlab_group_variable` diff --git a/docs/gmailfilter.md b/docs/gmailfilter.md new file mode 100644 index 000000000..dc881aff0 --- /dev/null +++ b/docs/gmailfilter.md @@ -0,0 +1,27 @@ +### Use with GmailFilter + +Support [Using Service Accounts](https://github.com/yamamoto-febc/terraform-provider-gmailfilter/blob/master/README.md#using-a-service-accountg-suite-users-only) or [Using Application Default Credentials](https://github.com/yamamoto-febc/terraform-provider-gmailfilter/blob/master/README.md#using-an-application-default-credential). + +Example: + +``` +# Using Service Accounts +export GOOGLE_CREDENTIALS=/path/to/client_secret.json +export IMPERSONATED_USER_EMAIL="foobar@example.com" + +# Using Application Default Credentials +gcloud auth application-default login \ + --client-id-file=client_secret.json \ + --scopes \ +https://www.googleapis.com/auth/gmail.labels,\ +https://www.googleapis.com/auth/gmail.settings.basic + +./terraformer import gmailfilter -r=filter,label +``` + +List of supported GmailFilter resources: + +* `label` + * `gmailfilter_label` +* `filter` + * `gmailfilter_filter` diff --git a/docs/grafana.md b/docs/grafana.md new file mode 100644 index 000000000..149a3dc26 --- /dev/null +++ b/docs/grafana.md @@ -0,0 +1,29 @@ +### Use with [Grafana](https://grafana.com) + +This provider uses the [terraform-provider-grafana](https://registry.terraform.io/providers/grafana/grafana/latest). + +#### Example + +``` +GRAFANA_AUTH=api_token GRAFANA_URL=https://stack.grafana.net ./terraformer import grafana -r=dashboards // Import with Grafana API token +GRAFANA_AUTH=username:password GRAFANA_URL=https://stack.grafana.net ./terraformer import grafana -r=dashboards // Import with HTTP basic auth +``` + +#### Configuration + +| Env variable | Description | Required | Default | +| -------------------------- | -------------------------------------------------------------------- | --- | - | +| GRAFANA_AUTH | API token or HTTP basic auth (if pattern is `username:password`) | yes | - | +| GRAFANA_URL | URL to the Grafana instance, e.g. https://stack.grafana.net | yes | - | +| GRAFANA_ORG_ID | Grafana organisation ID | no | 1 | +| HTTPS_TLS_KEY | Path to TLS key file | no | - | +| HTTPS_TLS_CERT | Path to TLS cert file | no | - | +| HTTPS_CA_CERT | Path to CA cert file | no | - | +| HTTPS_INSECURE_SKIP_VERIFY | Whether to skip TLS certificate validation (1 for true, 0 for false) | no | 0 | + +List of supported [Grafana](https://grafana.com) resources: + +* `dashboard` + * `grafana_dashboard` +* `folder` + * `grafana_folder` diff --git a/docs/heroku.md b/docs/heroku.md new file mode 100644 index 000000000..87474b4b2 --- /dev/null +++ b/docs/heroku.md @@ -0,0 +1,45 @@ +### Use with Heroku + +Example: + +``` +export HEROKU_EMAIL=[HEROKU_EMAIL] +export HEROKU_API_KEY=[HEROKU_API_KEY] +./terraformer import heroku -r app,addon +``` + +List of supported Heroku resources: + +* `account_feature` + * `heroku_account_feature` +* `addon` + * `heroku_addon` +* `addon_attachment` + * `heroku_addon_attachment` +* `app` + * `heroku_app` +* `app_config_association` + * `heroku_app_config_association` +* `app_feature` + * `heroku_app_feature` +* `app_webhook` + * `heroku_app_webhook` +* `build` + * `heroku_build` +* `cert` + * `heroku_cert` +* `domain` + * `heroku_domain` +* `drain` + * `heroku_drain` +* `formation` + * `heroku_formation` +* `pipeline` + * `heroku_pipeline` +* `pipeline_coupling` + * `heroku_pipeline_coupling` +* `team_collaborator` + * `heroku_team_collaborator` +* `team_member` + * `heroku_team_member` + diff --git a/docs/ibmcloud.md b/docs/ibmcloud.md new file mode 100644 index 000000000..421c0a7d5 --- /dev/null +++ b/docs/ibmcloud.md @@ -0,0 +1,141 @@ +### Use with IBM Cloud + +If you want to run Terraformer with the IBM Cloud provider plugin on your system, complete the following steps: + + +1. Export IBM Cloud API key as environment variables. + Example: + + ``` + export IC_API_KEY= + terraformer import ibm -r ibm_cos,ibm_iam.... + ``` +2. Use flag for Resource Group to classify resources accordingly. + Example: + + ``` + export IC_API_KEY= + terraformer import ibm --resources=ibm_is_vpc --resource_group=default + terraformer import ibm --resources=ibm_function --region=us-south + ``` +List of supported IBM Cloud resources: + +* `ibm_kp` + * `ibm_resource_instance` + * `ibm_kms_key` +* `ibm_cos` + * `ibm_resource_instance` + * `ibm_cos_bucket` +* `ibm_iam` + * `ibm_iam_user_policy` + * `ibm_iam_access_group` + * `ibm_iam_access_group_members` + * `ibm_iam_access_group_policy` + * `ibm_iam_access_group_dynamic_rule` + * `ibm_iam_service_id` + * `ibm_iam_authorization_policy` + * `ibm_iam_custom_role` + * `ibm_iam_service_policy` +* `ibm_container_vpc_cluster` + * `ibm_container_vpc_cluster` + * `ibm_container_vpc_worker_pool` +* `ibm_database_etcd` + * `ibm_database` +* `ibm_database_mongo` + * `ibm_database` +* `ibm_database_postgresql` + * `ibm_database` +* `ibm_database_rabbitmq` + * `ibm_database` +* `ibm_database_redis` + * `ibm_database` +* `ibm_is_instance_group` + * `ibm_is_instance_group` + * `ibm_is_instance_group_manager` + * `ibm_is_instance_group_manager_policy` +* `ibm_cis` + * `ibm_cis` + * `ibm_cis_dns_record` + * `ibm_cis_firewall` + * `ibm_cis_domain_settings` + * `ibm_cis_global_load_balancer` + * `ibm_cis_edge_functions_action` + * `ibm_cis_edge_functions_trigger` + * `ibm_cis_healthcheck` + * `ibm_cis_rate_limit` + * `ibm_cis_domain` + * `ibm_cis_origin_pool` + * `ibm_cis_waf_package` + * `ibm_cis_waf_group` + * `ibm_cis_page_rule` + * `ibm_cis_custom_page` + * `ibm_cis_range_app` + * `ibm_cis_certificate_order` + * `ibm_cis_routing` + * `ibm_cis_cache_settings` + * `ibm_cis_tls_settings` + * `ibm_cis_filter` +* `ibm_is_vpc` + * `ibm_is_vpc` + * `ibm_is_vpc_address_prefix` + * `ibm_is_vpc_route` + * `ibm_is_vpc_routing_table` + * `ibm_is_vpc_routing_table_route` +* `ibm_is_subnet` +* `ibm_is_instance` +* `ibm_is_security_group` + * `ibm_is_security_group` + * `ibm_is_security_group_rule` +* `ibm_is_network_acl` +* `ibm_is_public_gateway` +* `ibm_is_volume` +* `ibm_is_vpn_gateway` + * `ibm_is_vpn_gateway` + * `ibm_is_vpn_gateway_connections` +* `ibm_is_lb` + * `ibm_is_lb_pool` + * `ibm_is_lb_pool_member` + * `ibm_is_lb_listener` + * `ibm_is_lb_listener_policy` + * `ibm_is_lb_listener_policy_rule` +* `ibm_is_floating_ip` +* `ibm_is_flow_log` +* `ibm_is_ike_policy` +* `ibm_is_image` +* `ibm_is_instance_template` +* `ibm_is_ipsec_policy` +* `ibm_is_ssh_key` +* `ibm_function` + * `ibm_function_package` + * `ibm_function_action` + * `ibm_function_rule` + * `ibm_function_trigger` +* `ibm_private_dns` + * `ibm_resource_instance` + * `ibm_dns_zone` + * `ibm_dns_resource_record` + * `ibm_dns_permitted_network` + * `ibm_dns_glb_monitor` + * `ibm_dns_glb_pool` + * `ibm_dns_glb` +* `ibm_transit_gateway` + * `ibm_tg_gateway` + * `ibm_tg_connection` +* `ibm_direct_link` + * `ibm_dl_gateway` + * `ibm_dl_virtual_connection` + * `ibm_dl_provider_gateway` +* `ibm_container_cluster` + * `ibm_container_cluster` + * `ibm_container_worker_pool` + * `ibm_container_worker_pool_zone_attachment` +* `ibm_certificate_manager` + * `ibm_resource_instance` + * `ibm_certificate_manager_import` + * `ibm_certificate_manager_order` +* `ibm_vpe_gateway` + * `ibm_is_virtual_endpoint_gateway` + * `ibm_is_virtual_endpoint_gateway_ip` +* `ibm_satellite` + * `ibm_satellite_location` + * `ibm_satellite_host` diff --git a/docs/keycloak.md b/docs/keycloak.md new file mode 100644 index 000000000..156fd6c54 --- /dev/null +++ b/docs/keycloak.md @@ -0,0 +1,49 @@ +### Use with Keycloak + +Example: + +``` + export KEYCLOAK_URL=https://foo.bar.localdomain + export KEYCLOAK_CLIENT_ID=[KEYCLOAK_CLIENT_ID] + export KEYCLOAK_CLIENT_SECRET=[KEYCLOAK_CLIENT_SECRET] + + terraformer import keycloak --resources=realms + terraformer import keycloak --resources=realms --filter=realm=name1:name2:name3 + terraformer import keycloak --resources=realms --targets realmA,realmB +``` + +Here is the list of resources which are currently supported by Keycloak provider v.1.19.0: + +- `realms` + - `keycloak_default_groups` + - `keycloak_group` + - `keycloak_group_memberships` + - `keycloak_group_roles` + - `keycloak_ldap_full_name_mapper` + - `keycloak_ldap_group_mapper` + - `keycloak_ldap_hardcoded_group_mapper` + - `keycloak_ldap_hardcoded_role_mapper` + - `keycloak_ldap_msad_lds_user_account_control_mapper` + - `keycloak_ldap_msad_user_account_control_mapper` + - `keycloak_ldap_user_attribute_mapper` + - `keycloak_ldap_user_federation` + - `keycloak_openid_audience_protocol_mapper` + - `keycloak_openid_client` + - `keycloak_openid_client_default_scopes` + - `keycloak_openid_client_optional_scopes` + - `keycloak_openid_client_scope` + - `keycloak_openid_client_service_account_role` + - `keycloak_openid_full_name_protocol_mapper` + - `keycloak_openid_group_membership_protocol_mapper` + - `keycloak_openid_hardcoded_claim_protocol_mapper` + - `keycloak_openid_hardcoded_group_protocol_mapper` + - `keycloak_openid_hardcoded_role_protocol_mapper` (only for client roles) + - `keycloak_openid_user_attribute_protocol_mapper` + - `keycloak_openid_user_property_protocol_mapper` + - `keycloak_openid_user_realm_role_protocol_mapper` + - `keycloak_openid_user_client_role_protocol_mapper` + - `keycloak_openid_user_session_note_protocol_mapper` + - `keycloak_realm` + - `keycloak_required_action` + - `keycloak_role` + - `keycloak_user` diff --git a/docs/kubernetes.md b/docs/kubernetes.md new file mode 100644 index 000000000..f28615fae --- /dev/null +++ b/docs/kubernetes.md @@ -0,0 +1,49 @@ +### Use with Kubernetes + +Example: + +``` + terraformer import kubernetes --resources=deployments,services,storageclasses + terraformer import kubernetes --resources=deployments,services,storageclasses --filter=deployment=name1:name2:name3 +``` + +All Kubernetes resources that are currently supported by the Kubernetes provider, are also supported by this module. Here is the list of resources which are currently supported by Kubernetes provider v.1.4: + +* `clusterrolebinding` + * `kubernetes_cluster_role_binding` +* `configmaps` + * `kubernetes_config_map` +* `deployments` + * `kubernetes_deployment` +* `horizontalpodautoscalers` + * `kubernetes_horizontal_pod_autoscaler` +* `limitranges` + * `kubernetes_limit_range` +* `namespaces` + * `kubernetes_namespace` +* `persistentvolumes` + * `kubernetes_persistent_volume` +* `persistentvolumeclaims` + * `kubernetes_persistent_volume_claim` +* `pods` + * `kubernetes_pod` +* `replicationcontrollers` + * `kubernetes_replication_controller` +* `resourcequotas` + * `kubernetes_resource_quota` +* `secrets` + * `kubernetes_secret` +* `services` + * `kubernetes_service` +* `serviceaccounts` + * `kubernetes_service_account` +* `statefulsets` + * `kubernetes_stateful_set` +* `storageclasses` + * `kubernetes_storage_class` + +#### Known issues + +* Terraform Kubernetes provider is rejecting resources with ":" characters in their names (as they don't meet DNS-1123), while it's allowed for certain types in Kubernetes, e.g. ClusterRoleBinding. +* Because Terraform flatmap uses "." to detect the keys for unflattening the maps, some keys with "." in their names are being considered as the maps. +* Since the library assumes empty strings to be empty values (not "0"), there are some issues with optional integer keys that are restricted to be positive. diff --git a/docs/linode.md b/docs/linode.md new file mode 100644 index 000000000..c31ec3f9f --- /dev/null +++ b/docs/linode.md @@ -0,0 +1,32 @@ +### Use with Linode + +Example: + +``` +export LINODE_TOKEN=[LINODE_TOKEN] +./terraformer import linode -r instance +``` + +List of supported Linode resources: + +* `domain` + * `linode_domain` + * `linode_domain_record` +* `image` + * `linode_image` +* `instance` + * `linode_instance` +* `nodebalancer` + * `linode_nodebalancer` + * `linode_nodebalancer_config` + * `linode_nodebalancer_node` +* `rdns` + * `linode_rdns` +* `sshkey` + * `linode_sshkey` +* `stackscript` + * `linode_stackscript` +* `token` + * `linode_token` +* `volume` + * `linode_volume` diff --git a/docs/logz.md b/docs/logz.md new file mode 100644 index 000000000..7fe21a66a --- /dev/null +++ b/docs/logz.md @@ -0,0 +1,14 @@ +### Use with Logz.io + +Example: + +``` + LOGZIO_API_TOKEN=foobar LOGZIO_BASE_URL=https://api-eu.logz.io ./terraformer import logzio -r=alerts,alert_notification_endpoints // Import Logz.io alerts and alert notification endpoints +``` + +List of supported Logz.io resources: + +* `alerts` + * `logzio_alert` +* `alert_notification_endpoints` + * `logzio_endpoint` diff --git a/docs/mackerel.md b/docs/mackerel.md new file mode 100644 index 000000000..24f653d36 --- /dev/null +++ b/docs/mackerel.md @@ -0,0 +1,30 @@ +### Use with Mackerel + +Example: + +```bash + ./terraformer import mackerel --resources=service --api-key=YOUR_MACKEREL_API_KEY // or MACKEREL_API_KEY in env --app-key=YOUR_MACKEREL_API_KEY + ./terraformer import mackerel --resources=service --filter=service=name1:name2:name4 --api-key=YOUR_MACKEREL_API_KEY // or MACKEREL_API_KEY in env --app-key=YOUR_MACKEREL_API_KEY + ./terraformer import mackerel --resources=aws_integration --filter=aws_integration=id1:id2:id4 --api-key=YOUR_MACKEREL_API_KEY // or MACKEREL_API_KEY in env --app-key=YOUR_MACKEREL_API_KEY +``` + +List of supported Mackerel services: + +* `alert_group_setting` + * `mackerel_alert_group_setting` +* `aws_integration` + * `mackerel_aws_integration` + * Sensitive field `secret_key` is not generated and needs to be manually set + * Sensitive field `external_id` is not generated and needs to be manually set +* `channel` + * `mackerel_channel` +* `downtime` + * `mackerel_downtime` +* `monitor` + * `mackerel_monitor` +* `notification_group` + * `mackerel_notification_group` +* `role` + * `mackerel_role` +* `service` + * `mackerel_service` \ No newline at end of file diff --git a/docs/mikrotik.md b/docs/mikrotik.md new file mode 100644 index 000000000..643899b5e --- /dev/null +++ b/docs/mikrotik.md @@ -0,0 +1,18 @@ +### Use with [Mikrotik](https://wiki.mikrotik.com/wiki/Manual:TOC) + +This provider uses the [terraform-provider-mikrotik](https://github.com/ddelnano/terraform-provider-mikrotik). The terraformer provider was built by [Dom Del Nano](https://github.com/ddelnano). + +Example: + +``` +## Warning! You should not expose your mikrotik creds through your bash history. Export them to your shell in a safe way when doing this for real! + +MIKROTIK_HOST=router-hostname:8728 MIKROTIK_USER=username MIKROTIK_PASSWORD=password terraformer import mikrotik -r=dhcp_lease + +# Import only static IPs +MIKROTIK_HOST=router-hostname:8728 MIKROTIK_USER=username MIKROTIK_PASSWORD=password terraformer import mikrotik -r=dhcp_lease --filter='Name=dynamic;Value=false' +``` + +List of supported mikrotik resources: + +* `mikrotik_dhcp_lease` \ No newline at end of file diff --git a/docs/ns1.md b/docs/ns1.md new file mode 100644 index 000000000..52908a085 --- /dev/null +++ b/docs/ns1.md @@ -0,0 +1,17 @@ +### Use with NS1 + +Example: + +``` +$ export NS1_APIKEY=[NS1_APIKEY] +$ terraformer import ns1 -r zone,monitoringjob,team +``` + +List of supported NS1 resources: + +* `zone` + * `ns1_zone` +* `monitoringjob` + * `ns1_monitoringjob` +* `team` + * `ns1_team` \ No newline at end of file diff --git a/docs/octopus.md b/docs/octopus.md new file mode 100644 index 000000000..a8d5c5b6e --- /dev/null +++ b/docs/octopus.md @@ -0,0 +1,31 @@ +### Use with OctopusDeploy + +Example: + +``` +export OCTOPUS_CLI_SERVER=http://localhost:8081/ +export OCTOPUS_CLI_API_KEY=API-CK7DQ8BMJCUUBSHAJCDIATXUO + +terraformer import octopusdeploy --resources=tagsets +``` + +* `accounts` + * `octopusdeploy_account` +* `certificates` + * `octopusdeploy_certificate` +* `environments` + * `octopusdeploy_environment` +* `feeds` + * `octopusdeploy_feed` +* `libraryvariablesets` + * `octopusdeploy_library_variable_set` +* `lifecycle` + * `octopusdeploy_lifecycle` +* `project` + * `octopusdeploy_project` +* `projectgroups` + * `octopusdeploy_project_group` +* `projecttriggers` + * `octopusdeploy_project_deployment_target_trigger` +* `tagsets` + * `octopusdeploy_tag_set` diff --git a/docs/okta.md b/docs/okta.md new file mode 100644 index 000000000..964532b96 --- /dev/null +++ b/docs/okta.md @@ -0,0 +1,56 @@ +### Use with Okta + +Example: + +``` +$ export OKTA_ORG_NAME= +$ export OKTA_BASE_URL= +$ export OKTA_API_TOKEN= +$ terraformer import okta --resources=okta_user,okta_group +``` + +List of supported Okta services: + +* `user` + * `okta_user` +* `user_type` + * `okta_user_type` +* `group` + * `okta_group` +* `policy` + * `okta_policy_password` + * `okta_policy_rule_password` + * `okta_policy_mfa` + * `okta_policy_rule_mfa` + * `okta_policy_signon` + * `okta_policy_rule_signon` +* `authorization_server` + * `okta_auth_server` + * `okta_auth_server_scope` + * `okta_auth_server_claim` + * `okta_auth_server_policy` +* `app` + * `okta_app_auto_login` + * `okta_app_basic_auth` + * `okta_app_bookmark` + * `okta_app_oauth` + * `okta_app_saml` + * `okta_app_secure_password_store` + * `okta_app_swa` + * `okta_app_three_field` +* `event_hook` +* * `okta_event_hook` +* `factor` + * `okta_factor` +* `inline_hook` +* * `okta_inline_hook` +* `idp` + * `okta_idp_oidc` + * `okta_idp_saml` + * `okta_idp_social` +* `network_zone` + * `okta_network_zone` +* `template_sms` + * `okta_template_sms` +* `trusted_origin` + * `okta_trusted_orgin` diff --git a/docs/openstack.md b/docs/openstack.md new file mode 100644 index 000000000..d27f1f895 --- /dev/null +++ b/docs/openstack.md @@ -0,0 +1,19 @@ +### Use with OpenStack + +Example: + +``` + terraformer import openstack --resources=compute,networking --regions=RegionOne +``` + +List of supported OpenStack services: + +* `blockstorage` + * `openstack_blockstorage_volume_v1` + * `openstack_blockstorage_volume_v2` + * `openstack_blockstorage_volume_v3` +* `compute` + * `openstack_compute_instance_v2` +* `networking` + * `openstack_networking_secgroup_v2` + * `openstack_networking_secgroup_rule_v2` diff --git a/docs/opsgenie.md b/docs/opsgenie.md new file mode 100644 index 000000000..3c16b1735 --- /dev/null +++ b/docs/opsgenie.md @@ -0,0 +1,14 @@ +### Use with Opsgenie + +Example: + +``` + terraformer import opsgenie --resources=team,user --api-key=YOUR_API_KEY // or OPSGENIE_API_KEY in env +``` + +List of supported Opsgenie services: + +* `team` + * `opsgenie_team` +* `user` + * `opsgenie_user` diff --git a/docs/pagerduty.md b/docs/pagerduty.md new file mode 100644 index 000000000..44edee82c --- /dev/null +++ b/docs/pagerduty.md @@ -0,0 +1,28 @@ +### Use with PagerDuty + +Example: + +``` +./terraformer import pagerduty -r team,schedule,user -t YOUR_PAGERDUTY_TOKEN // or PAGERDUTY_TOKEN in env +``` +Instructions to obtain a Auth Token: https://developer.pagerduty.com/docs/rest-api-v2/authentication/ + +List of supported PagerDuty resources: + +* `business_service` + * `pagerduty_business_service` +* `escalation_policy` + * `pagerduty_escalation_policy` +* `ruleset` + * `pagerduty_ruleset` + * `pagerduty_ruleset_rule` +* `schedule` + * `pagerduty_schedule` +* `service` + * `pagerduty_service` + * `pagerduty_service_event_rule` +* `team` + * `pagerduty_team` + * `pagerduty_team_membership` +* `user` + * `pagerduty_user` diff --git a/docs/panos.md b/docs/panos.md new file mode 100644 index 000000000..a73954437 --- /dev/null +++ b/docs/panos.md @@ -0,0 +1,167 @@ +### Use with PAN-OS + +Example: + +``` + export PANOS_HOSTNAME=192.168.1.1 + export PANOS_USERNAME=[PANOS_USERNAME] + export PANOS_PASSWORD=[PANOS_PASSWORD] + + terraformer import panos --resources=firewall_device_config,firewall_networking,firewall_objects,firewall_policy +``` +The list of usable environment variables is the same as the [pango go-client](https://github.com/PaloAltoNetworks/pango): +* `PANOS_HOSTNAME` +* `PANOS_USERNAME` +* `PANOS_PASSWORD` +* `PANOS_API_KEY` +* `PANOS_PROTOCOL` +* `PANOS_PORT` +* `PANOS_TIMEOUT` +* `PANOS_TARGET` +* `PANOS_HEADERS` +* `PANOS_VERIFY_CERTIFICATE` +* `PANOS_LOGGING` + +Here is the list of resources which are currently supported: + +* `firewall_device_config` + * `panos_general_settings` + * `panos_telemetry` + * `panos_email_server_profile` + * `panos_http_server_profile` + * `panos_snmptrap_server_profile` + * `panos_syslog_server_profile` +* `firewall_networking` + * `panos_aggregate_interface` + * `panos_bfd_profile` + * `panos_bgp` + * `panos_bgp_aggregate` + * `panos_bgp_aggregate_advertise_filter` + * `panos_bgp_aggregate_suppress_filter` + * `panos_bgp_auth_profile` # The secret argument will contain "(incorrect)" + * `panos_bgp_conditional_adv` + * `panos_bgp_conditional_adv_advertise_filter` + * `panos_bgp_conditional_adv_non_exist_filter` + * `panos_bgp_dampening_profile` + * `panos_bgp_export_rule_group` + * `panos_bgp_import_rule_group` + * `panos_bgp_peer` + * `panos_bgp_peer_group` + * `panos_bgp_redist_rule` + * `panos_ethernet_interface` + * `panos_gre_tunnel` + * `panos_ike_crypto_profile` + * `panos_ike_gateway` + * `panos_ipsec_crypto_profile` + * `panos_ipsec_tunnel` + * `panos_ipsec_tunnel_proxy_id_ipv4` + * `panos_layer2_subinterface` + * `panos_layer3_subinterface` + * `panos_loopback_interface` + * `panos_management_profile` + * `panos_monitor_profile` + * `panos_redistribution_profile` + * `panos_static_route_ipv4` + * `panos_tunnel_interface` + * `panos_virtual_router` + * `panos_vlan` + * `panos_vlan_interface` + * `panos_zone` +* `firewall_objects` + * `panos_address_group` + * `panos_administrative_tag` + * `panos_application_group` + * `panos_application_object` + * `panos_edl` + * `panos_log_forwarding_profile` + * `panos_service_group` + * `panos_service_object` + * `panos_address_object` + * `panos_anti_spyware_security_profile` + * `panos_antivirus_security_profile` + * `panos_custom_data_pattern_object` + * `panos_data_filtering_security_profile` + * `panos_dos_protection_profile` + * `panos_dynamic_user_group` + * `panos_file_blocking_security_profile` + * `panos_url_filtering_security_profile` + * `panos_vulnerability_security_profile` + * `panos_wildfire_analysis_security_profile` +* `firewall_policy` + * `panos_nat_rule_group` + * `panos_pbf_rule_group` + * `panos_security_rule_group` +* `panorama_device_config` + * `panos_device_group_parent` + * `panos_panorama_device_group` + * `panos_panorama_email_server_profile` + * `panos_panorama_http_server_profile` + * `panos_panorama_snmptrap_server_profile` + * `panos_panorama_syslog_server_profile` + * `panos_panorama_template` + * `panos_panorama_template_stack` + * `panos_panorama_template_variable` +* `panorama_networking` + * `panos_panorama_aggregate_interface` + * `panos_panorama_bfd_profile` + * `panos_panorama_bgp` + * `panos_panorama_bgp_aggregate` + * `panos_panorama_bgp_aggregate_advertise_filter` + * `panos_panorama_bgp_aggregate_suppress_filter` + * `panos_panorama_bgp_auth_profile` # The secret argument will contain "(incorrect)" + * `panos_panorama_bgp_conditional_adv` + * `panos_panorama_bgp_conditional_adv_advertise_filter` + * `panos_panorama_bgp_conditional_adv_non_exist_filter` + * `panos_panorama_bgp_dampening_profile` + * `panos_panorama_bgp_export_rule_group` + * `panos_panorama_bgp_import_rule_group` + * `panos_panorama_bgp_peer` + * `panos_panorama_bgp_peer_group` + * `panos_panorama_bgp_redist_rule` + * `panos_panorama_ethernet_interface` + * `panos_panorama_gre_tunnel` + * `panos_panorama_ike_crypto_profile` + * `panos_panorama_ike_gateway` + * `panos_panorama_ipsec_crypto_profile` + * `panos_panorama_ipsec_tunnel` + * `panos_panorama_ipsec_tunnel_proxy_id_ipv4` + * `panos_panorama_layer2_subinterface` + * `panos_panorama_layer3_subinterface` + * `panos_panorama_loopback_interface` + * `panos_panorama_management_profile` + * `panos_panorama_monitor_profile` + * `panos_panorama_redistribution_profile` + * `panos_panorama_static_route_ipv4` + * `panos_panorama_tunnel_interface` + * `panos_panorama_virtual_router` + * `panos_panorama_vlan` + * `panos_panorama_vlan_interface` + * `panos_panorama_zone` +* `panorama_objects` + * `panos_panorama_address_group` + * `panos_panorama_administrative_tag` + * `panos_panorama_application_group` + * `panos_panorama_application_object` + * `panos_panorama_edl` + * `panos_panorama_log_forwarding_profile` + * `panos_panorama_service_group` + * `panos_panorama_service_object` + * `panos_address_object` + * `panos_anti_spyware_security_profile` + * `panos_antivirus_security_profile` + * `panos_custom_data_pattern_object` + * `panos_data_filtering_security_profile` + * `panos_dos_protection_profile` + * `panos_dynamic_user_group` + * `panos_file_blocking_security_profile` + * `panos_url_filtering_security_profile` + * `panos_vulnerability_security_profile` + * `panos_wildfire_analysis_security_profile` +* `panorama_plugins` + * `panos_panorama_gcp_account` + * `panos_panorama_gke_cluster` + * `panos_panorama_gke_cluster_group` +* `panorama_policy` + * `panos_panorama_nat_rule_group` + * `panos_panorama_pbf_rule_group` + * `panos_panorama_security_rule_group` diff --git a/docs/rabbitmq.md b/docs/rabbitmq.md new file mode 100644 index 000000000..f2ce35f9a --- /dev/null +++ b/docs/rabbitmq.md @@ -0,0 +1,29 @@ +### Use with RabbitMQ + +Example: + +``` + export RABBITMQ_SERVER_URL=http://foo.bar.localdomain:15672 + export RABBITMQ_USERNAME=[RABBITMQ_USERNAME] + export RABBITMQ_PASSWORD=[RABBITMQ_PASSWORD] + + terraformer import rabbitmq --resources=vhosts,queues,exchanges + terraformer import rabbitmq --resources=vhosts,queues,exchanges --filter=vhost=name1:name2:name3 +``` + +All RabbitMQ resources that are currently supported by the RabbitMQ provider, are also supported by this module. Here is the list of resources which are currently supported by RabbitMQ provider v.1.1.0: + +* `bindings` + * `rabbitmq_binding` +* `exchanges` + * `rabbitmq_exchange` +* `permissions` + * `rabbitmq_permissions` +* `policies` + * `rabbitmq_policy` +* `queues` + * `rabbitmq_queue` +* `users` + * `rabbitmq_user` +* `vhosts` + * `rabbitmq_vhost` diff --git a/docs/relic.md b/docs/relic.md new file mode 100644 index 000000000..6a47dfa6d --- /dev/null +++ b/docs/relic.md @@ -0,0 +1,21 @@ +### Use with New Relic + +Example: + +``` +./terraformer import newrelic -r alert,dashboard,infra,synthetics --api-key=NRAK-XXXXXXXX --account-id=XXXXX +``` + +List of supported New Relic resources: + +* `alert` + * `newrelic_alert_channel` + * `newrelic_alert_condition` + * `newrelic_alert_policy` +* `dashboard` + * `newrelic_dashboard` +* `infra` + * `newrelic_infra_alert_condition` +* `synthetics` + * `newrelic_synthetics_monitor` + * `newrelic_synthetics_alert_condition` diff --git a/docs/tencentcloud.md b/docs/tencentcloud.md new file mode 100644 index 000000000..699ec4483 --- /dev/null +++ b/docs/tencentcloud.md @@ -0,0 +1,55 @@ +### Use with TencentCloud + +Example: + +``` +$ export TENCENTCLOUD_SECRET_ID= +$ export TENCENTCLOUD_SECRET_KEY= +$ terraformer import tencentcloud --resources=cvm,cbs --regions=ap-guangzhou +``` + +List of supported TencentCloud services: + +* `as` + * `tencentcloud_as_scaling_group` + * `tencentcloud_as_scaling_config` +* `cbs` + * `tencentcloud_cbs_storage` +* `cdn` + * `tencentcloud_cdn_domain` +* `cfs` + * `tencentcloud_cfs_file_system` +* `clb` + * `tencentcloud_clb_instance` +* `cos` + * `tencentcloud_cos_bucket` +* `cvm` + * `tencentcloud_instance` +* `elasticsearch` + * `tencentcloud_elasticsearch_instance` +* `gaap` + * `tencentcloud_gaap_proxy` + * `tencentcloud_gaap_realserver` +* `key_pair` + * `tencentcloud_key_pair` +* `mongodb` + * `tencentcloud_mongodb_instance` +* `mysql` + * `tencentcloud_mysql_instance` + * `tencentcloud_mysql_readonly_instance` +* `redis` + * `tencentcloud_redis_instance` +* `scf` + * `tencentcloud_scf_function` +* `security_group` + * `tencentcloud_security_group` +* `ssl` + * `tencentcloud_ssl_certificate` +* `subnet` + * `tencentcloud_subnet` +* `tcaplus` + * `tencentcloud_tcaplus_cluster` +* `vpc` + * `tencentcloud_vpc` +* `vpc` + * `tencentcloud_vpn_gateway` diff --git a/docs/vault.md b/docs/vault.md new file mode 100644 index 000000000..84c4c33df --- /dev/null +++ b/docs/vault.md @@ -0,0 +1,87 @@ +### Use with Vault + +Example: + +``` + ./terraformer import vault --resources=aws_secret_backend_role --token=YOUR_VAULT_TOKEN // or VAULT_TOKEN in env --address=YOUR_VAULT_ADDRESS // or VAULT_ADDR in env + ./terraformer import vault --resources=policy --filter=policy=id1:id2:id4 --token=YOUR_VAULT_TOKEN // or VAULT_TOKEN in env --address=YOUR_VAULT_ADDRESS // or VAULT_ADDR in env +``` + +List of supported Vault resources: + +* `ad_secret_backend` + * `ad_secret_backend` +* `ad_secret_backend_role` + * `ad_secret_backend_role` +* `alicloud_auth_backend_role` + * `alicloud_auth_backend_role` +* `approle_auth_backend_role` + * `approle_auth_backend_role` +* `aws_auth_backend_role` + * `aws_auth_backend_role` +* `aws_secret_backend` + * `aws_secret_backend` +* `aws_secret_backend_role` + * `aws_secret_backend_role` +* `azure_auth_backend_role` + * `azure_auth_backend_role` +* `azure_secret_backend` + * `azure_secret_backend` +* `azure_secret_backend_role` + * `azure_secret_backend_role` +* `cert_auth_backend_role` + * `cert_auth_backend_role` +* `consul_secret_backend` + * `consul_secret_backend` +* `consul_secret_backend_role` + * `consul_secret_backend_role` +* `database_secret_backend_role` + * `database_secret_backend_role` +* `gcp_auth_backend` + * `gcp_auth_backend` +* `gcp_auth_backend_role` + * `gcp_auth_backend_role` +* `gcp_secret_backend` + * `gcp_secret_backend` +* `generic_secret` + * `generic_secret` +* `github_auth_backend` + * `github_auth_backend` +* `jwt_auth_backend` + * `jwt_auth_backend` +* `jwt_auth_backend_role` + * `jwt_auth_backend_role` +* `kubernetes_auth_backend_role` + * `kubernetes_auth_backend_role` +* `ldap_auth_backend` + * `ldap_auth_backend` +* `ldap_auth_backend_group` + * `ldap_auth_backend_group` +* `ldap_auth_backend_user` + * `ldap_auth_backend_user` +* `nomad_secret_backend` + * `nomad_secret_backend` +* `okta_auth_backend` + * `okta_auth_backend` +* `okta_auth_backend_group` + * `okta_auth_backend_group` +* `okta_auth_backend_user` + * `okta_auth_backend_user` +* `pki_secret_backend` + * `pki_secret_backend` +* `pki_secret_backend_role` + * `pki_secret_backend_role` +* `policy` + * `policy` +* `rabbitmq_secret_backend` + * `rabbitmq_secret_backend` +* `rabbitmq_secret_backend_role` + * `rabbitmq_secret_backend_role` +* `ssh_secret_backend_role` + * `ssh_secret_backend_role` +* `terraform_cloud_secret_backend` + * `terraform_cloud_secret_backend` +* `token_auth_backend_role` + * `token_auth_backend_role` + +[1]: https://github.com/GoogleCloudPlatform/terraformer/blob/master/README.md#filtering diff --git a/docs/vultr.md b/docs/vultr.md new file mode 100644 index 000000000..0ed659939 --- /dev/null +++ b/docs/vultr.md @@ -0,0 +1,35 @@ +### Use with Vultr + +Example: + +``` +export VULTR_API_KEY=[VULTR_API_KEY] +./terraformer import vultr -r server +``` + +List of supported Vultr resources: + +* `bare_metal_server` + * `vultr_bare_metal_server` +* `block_storage` + * `vultr_block_storage` +* `dns_domain` + * `vultr_dns_domain` + * `vultr_dns_record` +* `firewall_group` + * `vultr_firewall_group` + * `vultr_firewall_rule` +* `network` + * `vultr_network` +* `reserved_ip` + * `vultr_reserved_ip` +* `server` + * `vultr_server` +* `snapshot` + * `vultr_snapshot` +* `ssh_key` + * `vultr_ssh_key` +* `startup_script` + * `vultr_startup_script` +* `user` + * `vultr_user` diff --git a/docs/xen.md b/docs/xen.md new file mode 100644 index 000000000..7b5d5dd05 --- /dev/null +++ b/docs/xen.md @@ -0,0 +1,16 @@ +### Use with [Xen Orchestra](https://xen-orchestra.com/) + +This provider uses the [terraform-provider-xenorchestra](https://github.com/ddelnano/terraform-provider-xenorchestra). The terraformer provider was built by [Dom Del Nano](https://github.com/ddelnano) on behalf of [Vates SAS](https://vates.fr/) who is sponsoring Dom to work on the project. + +Example: + +``` +## Warning! You should not expose your xenorchestra creds through your bash history. Export them to your shell in a safe way when doing this for real! + +XOA_URL=ws://your-xenorchestra-domain XOA_USER=username XOA_PASSWORD=password terraformer import xenorchestra -r=acl +``` + +List of supported xenorchestra resources: + +* `xenorchestra_acl` +* `xenorchestra_resource_set` diff --git a/docs/yandex.md b/docs/yandex.md new file mode 100644 index 000000000..01c9d469f --- /dev/null +++ b/docs/yandex.md @@ -0,0 +1,23 @@ +### Use with Yandex + +Example: + +``` +export YC_TOKEN=[YANDEX_CLOUD_OAUTH_TOKEN] +export YC_FOLDER_ID=[YANDEX_FOLDER_ID] +./terraformer import yandex -r subnet +``` + +List of supported Yandex resources: + +* `instance` + * `yandex_compute_instance` +* `disk` + * `yandex_compute_disk` +* `subnet` + * `yandex_vpc_subnet` +* `network` + * `yandex_vpc_network` + +Your `tf` and `tfstate` files are written by default to +`generated/yandex/service`. \ No newline at end of file diff --git a/go.mod b/go.mod index 198d12039..4dd91b8fe 100644 --- a/go.mod +++ b/go.mod @@ -1,61 +1,337 @@ module github.com/GoogleCloudPlatform/terraformer -go 1.15 +go 1.17 require ( - cloud.google.com/go v0.71.0 + cloud.google.com/go v0.77.0 cloud.google.com/go/logging v1.1.2 - cloud.google.com/go/storage v1.12.0 - github.com/Azure/azure-sdk-for-go v42.0.0+incompatible + cloud.google.com/go/storage v1.14.0 + github.com/Azure/azure-sdk-for-go v57.1.0+incompatible github.com/Azure/azure-storage-blob-go v0.10.0 - github.com/Azure/go-autorest/autorest v0.11.12 - github.com/DataDog/datadog-api-client-go v1.0.0-beta.9 + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-autorest/autorest v0.11.20 + github.com/DataDog/datadog-api-client-go v1.4.0 + github.com/IBM-Cloud/bluemix-go v0.0.0-20210203095940-db28d5e07b55 + github.com/IBM/go-sdk-core/v3 v3.3.1 + github.com/IBM/go-sdk-core/v4 v4.9.0 + github.com/IBM/ibm-cos-sdk-go v1.5.0 + github.com/IBM/keyprotect-go-client v0.6.0 + github.com/IBM/networking-go-sdk v0.19.0 + github.com/IBM/platform-services-go-sdk v0.19.1 + github.com/IBM/vpc-go-sdk v0.4.1 + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/OctopusDeploy/go-octopusdeploy v1.6.0 - github.com/aliyun/alibaba-cloud-sdk-go v1.60.295 + github.com/PaloAltoNetworks/pango v0.6.0 + github.com/SAP/go-hdb v0.105.2 // indirect + github.com/SermoDigital/jose v0.9.1 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.61.1247 github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible - github.com/aws/aws-sdk-go v1.30.19 - github.com/aws/aws-sdk-go-v2 v0.24.0 + github.com/apache/openwhisk-client-go v0.0.0-20210106144548-17d556327cd3 + github.com/aws/aws-sdk-go-v2 v1.11.0 + github.com/aws/aws-sdk-go-v2/config v1.1.4 + github.com/aws/aws-sdk-go-v2/credentials v1.1.4 + github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.2.0 + github.com/aws/aws-sdk-go-v2/service/acm v1.2.1 + github.com/aws/aws-sdk-go-v2/service/apigateway v1.2.1 + github.com/aws/aws-sdk-go-v2/service/appsync v1.2.1 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.3.1 + github.com/aws/aws-sdk-go-v2/service/batch v1.3.1 + github.com/aws/aws-sdk-go-v2/service/budgets v1.1.3 + github.com/aws/aws-sdk-go-v2/service/cloud9 v1.1.3 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.3.0 + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.3.0 + github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.1.3 + github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.2.1 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.3.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatchevents v1.2.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.2.3 + github.com/aws/aws-sdk-go-v2/service/codebuild v1.2.1 + github.com/aws/aws-sdk-go-v2/service/codecommit v1.1.3 + github.com/aws/aws-sdk-go-v2/service/codedeploy v1.2.1 + github.com/aws/aws-sdk-go-v2/service/codepipeline v1.2.1 + github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.2.1 + github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.2.1 + github.com/aws/aws-sdk-go-v2/service/configservice v1.3.0 + github.com/aws/aws-sdk-go-v2/service/datapipeline v1.1.3 + github.com/aws/aws-sdk-go-v2/service/devicefarm v1.1.3 + github.com/aws/aws-sdk-go-v2/service/docdb v1.9.0 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.2.1 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.3.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.2.1 + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.2.0 + github.com/aws/aws-sdk-go-v2/service/ecs v1.2.1 + github.com/aws/aws-sdk-go-v2/service/efs v1.2.1 + github.com/aws/aws-sdk-go-v2/service/eks v1.2.1 + github.com/aws/aws-sdk-go-v2/service/elasticache v1.2.1 + github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.2.1 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.2.1 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.2.1 + github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.2.1 + github.com/aws/aws-sdk-go-v2/service/emr v1.2.1 + github.com/aws/aws-sdk-go-v2/service/firehose v1.2.1 + github.com/aws/aws-sdk-go-v2/service/glue v1.3.0 + github.com/aws/aws-sdk-go-v2/service/iam v1.3.0 + github.com/aws/aws-sdk-go-v2/service/iot v1.2.0 + github.com/aws/aws-sdk-go-v2/service/kafka v1.2.1 + github.com/aws/aws-sdk-go-v2/service/kinesis v1.2.1 + github.com/aws/aws-sdk-go-v2/service/kms v1.2.2 + github.com/aws/aws-sdk-go-v2/service/lambda v1.2.1 + github.com/aws/aws-sdk-go-v2/service/mediapackage v1.2.1 + github.com/aws/aws-sdk-go-v2/service/mediastore v1.1.4 + github.com/aws/aws-sdk-go-v2/service/opsworks v1.2.2 + github.com/aws/aws-sdk-go-v2/service/organizations v1.2.1 + github.com/aws/aws-sdk-go-v2/service/qldb v1.1.3 + github.com/aws/aws-sdk-go-v2/service/rds v1.11.0 + github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.2.1 + github.com/aws/aws-sdk-go-v2/service/route53 v1.3.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.4.0 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.2.1 + github.com/aws/aws-sdk-go-v2/service/securityhub v1.2.1 + github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.2.1 + github.com/aws/aws-sdk-go-v2/service/ses v1.2.1 + github.com/aws/aws-sdk-go-v2/service/sfn v1.2.1 + github.com/aws/aws-sdk-go-v2/service/sns v1.2.1 + github.com/aws/aws-sdk-go-v2/service/sqs v1.3.0 + github.com/aws/aws-sdk-go-v2/service/ssm v1.3.0 + github.com/aws/aws-sdk-go-v2/service/sts v1.2.1 + github.com/aws/aws-sdk-go-v2/service/swf v1.2.2 + github.com/aws/aws-sdk-go-v2/service/waf v1.1.4 + github.com/aws/aws-sdk-go-v2/service/wafregional v1.2.1 + github.com/aws/aws-sdk-go-v2/service/workspaces v1.2.1 + github.com/aws/aws-sdk-go-v2/service/xray v1.2.1 github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cloudflare/cloudflare-go v0.13.5 - github.com/ddelnano/terraform-provider-mikrotik v0.0.0-20200501162830-a217572b326c + github.com/cloudflare/cloudflare-go v0.13.6 + github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect + github.com/containerd/continuity v0.1.0 // indirect + github.com/ddelnano/terraform-provider-mikrotik/client v0.0.0-20210401060029-7f652169b2c4 + github.com/ddelnano/terraform-provider-xenorchestra/client v0.0.0-20210401070256-0d721c6762ef + github.com/denisenkom/go-mssqldb v0.10.0 // indirect github.com/denverdino/aliyungo v0.0.0-20200327235253-d59c209c7e93 - github.com/digitalocean/godo v1.35.1 + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/digitalocean/godo v1.57.0 + github.com/docker/go-connections v0.4.0 // indirect github.com/dollarshaveclub/new-relic-synthetics-go v0.0.0-20170605224734-4dc3dd6ae884 - github.com/fastly/go-fastly v1.15.0 - github.com/google/go-github/v25 v25.1.3 - github.com/gophercloud/gophercloud v0.13.0 + github.com/duosecurity/duo_api_golang v0.0.0-20201112143038-0e07e9f869e3 // indirect + github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect + github.com/fastly/go-fastly/v5 v5.1.2 + github.com/fatih/structs v1.1.0 // indirect + github.com/gocql/gocql v0.0.0-20210707082121-9a3953d1826d // indirect + github.com/google/go-github/v35 v35.1.0 + github.com/gophercloud/gophercloud v0.17.0 + github.com/grafana/grafana-api-golang-client v0.0.0-20210218192924-9ccd2365d2a6 github.com/hashicorp/go-azure-helpers v0.10.0 - github.com/hashicorp/go-hclog v0.14.1 - github.com/hashicorp/go-plugin v1.3.0 + github.com/hashicorp/go-cleanhttp v0.5.2 + github.com/hashicorp/go-hclog v0.16.2 + github.com/hashicorp/go-memdb v1.3.2 // indirect + github.com/hashicorp/go-plugin v1.4.1 github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/terraform v0.12.29 + github.com/hashicorp/terraform v0.12.31 + github.com/hashicorp/vault v0.10.4 + github.com/heimweh/go-pagerduty v0.0.0-20210930203304-530eff2acdc6 github.com/heroku/heroku-go/v5 v5.1.0 + github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 // indirect github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 - github.com/jmespath/go-jmespath v0.3.0 + github.com/jefferai/jsonx v1.0.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 github.com/jonboydell/logzio_client v1.2.0 - github.com/labd/commercetools-go-sdk v0.0.0-20200309143931-ca72e918a79d - github.com/linode/linodego v0.24.0 + github.com/labd/commercetools-go-sdk v0.3.1 + github.com/linode/linodego v0.24.1 + github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 github.com/mrparkers/terraform-provider-keycloak v0.0.0-20200506151941-509881368409 + github.com/nicksnyder/go-i18n v1.10.1 // indirect github.com/ns1/ns1-go v2.4.0+incompatible + github.com/okta/okta-sdk-golang/v2 v2.6.3-0.20210923165359-20aeac44ab01 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v1.0.1 // indirect + github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.8 + github.com/ory/dockertest v3.3.5+incompatible // indirect + github.com/packethost/packngo v0.9.0 github.com/paultyng/go-newrelic/v4 v4.10.0 github.com/pkg/errors v0.9.1 - github.com/smartystreets/goconvey v1.6.4 // indirect - github.com/spf13/cobra v1.0.0 + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/spf13/cobra v1.1.1 github.com/spf13/pflag v1.0.5 + github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible + github.com/tencentyun/cos-go-sdk-v5 v0.7.19 github.com/vultr/govultr v0.5.0 + github.com/xanzy/go-gitlab v0.50.2 github.com/yandex-cloud/go-genproto v0.0.0-20200722140432-762fe965ce77 github.com/yandex-cloud/go-sdk v0.0.0-20200722140627-2194e5077f13 - github.com/zclconf/go-cty v1.7.0 + github.com/zclconf/go-cty v1.8.4 github.com/zorkian/go-datadog-api v2.30.0+incompatible - golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 - golang.org/x/text v0.3.4 + golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 + golang.org/x/text v0.3.6 gonum.org/v1/gonum v0.7.0 - google.golang.org/api v0.35.0 - google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba + google.golang.org/api v0.40.0 + google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 gopkg.in/jarcoal/httpmock.v1 v1.0.0-00010101000000-000000000000 // indirect - k8s.io/apimachinery v0.17.5 - k8s.io/client-go v0.17.5 - k8s.io/utils v0.0.0-20191218082557-f07c713de883 // indirect + gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect + k8s.io/apimachinery v0.21.0 + k8s.io/client-go v0.21.0 +) + +require ( + github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62 + github.com/IBM/go-sdk-core v1.1.0 + github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 // indirect + github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect + github.com/mackerelio/mackerel-client-go v0.19.0 + github.com/okta/terraform-provider-okta v0.0.0-20210924173942-a5a664459d3b + github.com/zclconf/go-cty-yaml v1.0.2 // indirect +) + +require ( + github.com/Azure/azure-pipeline-go v0.2.2 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.2.0 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/IBM/go-sdk-core/v5 v5.5.1 // indirect + github.com/Masterminds/goutils v1.1.0 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/agext/levenshtein v1.2.2 // indirect + github.com/apparentlymart/go-cidr v1.1.0 // indirect + github.com/apparentlymart/go-textseg/v12 v12.0.0 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect + github.com/aws/aws-sdk-go v1.37.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.1.4 // indirect + github.com/aws/smithy-go v1.9.0 // indirect + github.com/beevik/etree v1.1.0 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect + github.com/bmatcuk/doublestar v1.1.5 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/crewjam/saml v0.4.5 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dghubble/sling v1.1.0 // indirect + github.com/dimchansky/utfbom v1.1.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/fatih/color v1.7.0 // indirect + github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/logr v0.4.0 // indirect + github.com/go-openapi/errors v0.19.8 // indirect + github.com/go-openapi/strfmt v0.20.1 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect + github.com/go-routeros/routeros v0.0.0-20210123142807-2a44d57c6730 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/gofrs/uuid v3.2.0+incompatible // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/jsonapi v0.0.0-20201022225600-f822737867f6 // indirect + github.com/google/uuid v1.2.0 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/googleapis/gnostic v0.4.1 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-getter v1.5.3 // indirect + github.com/hashicorp/go-multierror v1.0.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.0 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-sockaddr v1.0.0 // indirect + github.com/hashicorp/go-uuid v1.0.1 // indirect + github.com/hashicorp/go-version v1.3.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl/v2 v2.8.2 // indirect + github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 // indirect + github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jonboulle/clockwork v0.2.1 // indirect + github.com/json-iterator/go v1.1.10 // indirect + github.com/jstemmer/go-junit-report v0.9.1 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/klauspost/compress v1.11.2 // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e // indirect + github.com/mattn/go-colorable v0.1.4 // indirect + github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d // indirect + github.com/mattn/go-isatty v0.0.10 // indirect + github.com/mitchellh/cli v1.1.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.0.4 // indirect + github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/mitchellh/hashstructure v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/mozillazg/go-httpheader v0.2.1 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 // indirect + github.com/pborman/uuid v1.2.0 // indirect + github.com/pelletier/go-toml v1.7.0 // indirect + github.com/posener/complete v1.2.1 // indirect + github.com/russellhaering/goxmldsig v1.1.0 // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sourcegraph/jsonrpc2 v0.0.0-20210201082850-366fbb520750 // indirect + github.com/spf13/afero v1.2.2 // indirect + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + github.com/ulikunitz/xz v0.5.8 // indirect + github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect + github.com/vmihailenco/tagparser v0.1.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.0.2 // indirect + github.com/xdg-go/stringprep v1.0.2 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.7.2 // indirect + go.opencensus.io v0.22.5 // indirect + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect + golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect + golang.org/x/mod v0.4.1 // indirect + golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + golang.org/x/tools v0.1.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/grpc v1.35.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect + gopkg.in/go-playground/validator.v9 v9.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/api v0.21.0 // indirect + k8s.io/klog/v2 v2.8.0 // indirect + k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) replace gopkg.in/jarcoal/httpmock.v1 => github.com/jarcoal/httpmock v1.0.5 diff --git a/go.sum b/go.sum index 4ec2dfc31..9336436b6 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ -9fans.net/go v0.0.0-20181112161441-237454027057/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= -9fans.net/go v0.0.2/go.mod h1:lfPdxjq9v8pVQXUMBCx5EO5oLXWQFlKRQgs1kEkjoIM= +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -11,72 +10,71 @@ cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6T cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.61.0/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.66.0 h1:DZeAkuQGQqnm9Xv36SbMJEU8aFBz4wL04UpMWPWwjzg= -cloud.google.com/go v0.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko= -cloud.google.com/go v0.71.0 h1:2ha722Z08cmRa0orJrzBaszYQcLbLFcsZHsGSj/kIF4= cloud.google.com/go v0.71.0/go.mod h1:qZfY4Y7AEIQwG/fQYD3xrxLNkQZ0Xzf3HGeqCkA6LVM= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ= +cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/logging v1.1.2 h1:KNALX0NZn8UJhqKnqoHxhMqyoZfBZoh5wF7CQJZ5XrU= cloud.google.com/go/logging v1.1.2/go.mod h1:KrljuAHIw631j9+QXsnq9vDwsrwmdxfGpivMR68M7DY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0 h1:86K1Gel7BQ9/WmNWn7dTKMvTLFzwtBe5FNqYbi9X35g= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.12.0 h1:4y3gHptW1EHVtcPAVE0eBBlFuGqEejTTG3KdIE0lUX4= -cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho= +cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v42.0.0+incompatible h1:yz6sFf5bHZ+gEOQVuK5JhPqTTAmv+OvSLSaqgzqaCwY= -github.com/Azure/azure-sdk-for-go v42.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v57.1.0+incompatible h1:TKQ3ieyB0vVKkF6t9dsWbMjq56O1xU3eh3Ec09v6ajM= +github.com/Azure/azure-sdk-for-go v57.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.20 h1:s8H1PbCZSqg/DH7JMlOz6YMig6htWLNPsjDdlLqCx3M= +github.com/Azure/go-autorest/autorest v0.11.20/go.mod h1:o3tqFY+QR40VOlk+pV4d77mORO64jOXSgEnPQgLK6JY= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.3 h1:O1AGG9Xig71FxdX9HO5pGNyZ7TbSyHaVg+5eJO/jSGw= github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/cli v0.2.0 h1:pSwNMF0qotgehbQNllUWwJ4V3vnrLKOzHrwDLEZK904= github.com/Azure/go-autorest/autorest/azure/cli v0.2.0/go.mod h1:WWTbGPvkAg3I4ms2j2s+Zr5xCGwGqTQh+6M2ZqOczkE= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= @@ -84,11 +82,10 @@ github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yK github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= @@ -97,41 +94,88 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= -github.com/DataDog/datadog-api-client-go v1.0.0-beta.9 h1:TsOhRZ1r0WptlynSSBp8EuBT4vPRWNzYwbXrMGV0Eto= -github.com/DataDog/datadog-api-client-go v1.0.0-beta.9/go.mod h1:/bMeu+q33QzX2JuO5PkGkhU1VYOXIXKEPF6Ck4yR06M= -github.com/DataDog/datadog-go v3.6.0+incompatible h1:ILg7c5Y1KvZFDOaVS0higGmJ5Fal5O1KQrkrT9j6dSM= -github.com/DataDog/datadog-go v3.6.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-api-client-go v1.4.0 h1:EpiKfVg8aUdZB8ovvqIqiVC8Ox4kpcemNIIJ/5TZsXo= +github.com/DataDog/datadog-api-client-go v1.4.0/go.mod h1:QzaQF1cDO1/BIQG1fz14VrY+6RECUGkiwzDCtVbfP5c= +github.com/IBM-Cloud/bluemix-go v0.0.0-20210203095940-db28d5e07b55 h1:sUpBb2/GC8L6UOKDnbEZLRTxQB2RQgMv1mxbnOHOQW4= +github.com/IBM-Cloud/bluemix-go v0.0.0-20210203095940-db28d5e07b55/go.mod h1:kqTYO0mts71aa8PVwviaKlCKYud/NbEkFIqU8aHH3/g= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62 h1:MOkcr6qQGk4tY542ZJ1DggVh2WUP72EEyLB79llFVH8= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20210705152127-41ca00fc9a62/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= +github.com/IBM/go-sdk-core v1.1.0 h1:pV73lZqr9r1xKb3h08c1uNG3AphwoV5KzUzhS+pfEqY= +github.com/IBM/go-sdk-core v1.1.0/go.mod h1:2pcx9YWsIsZ3I7kH+1amiAkXvLTZtAq9kbxsfXilSoY= +github.com/IBM/go-sdk-core/v3 v3.3.1 h1:DoXjP1+Wm8Yd4XJsvBMRcYLvQwSLFnzKlMjSrg3Rzpw= +github.com/IBM/go-sdk-core/v3 v3.3.1/go.mod h1:lk9eOzNbNltPf3CBpcg1Ewkhw4qC3u2QCCKDRsUA2M0= +github.com/IBM/go-sdk-core/v4 v4.5.1/go.mod h1:lTUXbqIX6/aAbSCkP6q59+dyFsTwZAc0ewRS2vJWVbg= +github.com/IBM/go-sdk-core/v4 v4.9.0 h1:OkSg5kaEfVoNuBA4IsIOz8Ur5rbGHbWxmWCZ7nK/oc0= +github.com/IBM/go-sdk-core/v4 v4.9.0/go.mod h1:DbQ+3pFoIjxGGTEiA9zQ2V0cemMNmFMkLBBnR729HKg= +github.com/IBM/go-sdk-core/v5 v5.4.5/go.mod h1:Sn+z+qTDREQvCr+UFa22TqqfXNxx3o723y8GsfLV8e0= +github.com/IBM/go-sdk-core/v5 v5.5.1 h1:Hb4xB1BL8L6uCnskIqSCxF9wLfOmj4+sVzM5vFtuhs4= +github.com/IBM/go-sdk-core/v5 v5.5.1/go.mod h1:Sn+z+qTDREQvCr+UFa22TqqfXNxx3o723y8GsfLV8e0= +github.com/IBM/ibm-cos-sdk-go v1.5.0 h1:YCmAgsdtp/irQep5g+62OvjLNj35tMXLqTC5jQ+YjWo= +github.com/IBM/ibm-cos-sdk-go v1.5.0/go.mod h1:4mqv/ejW1PKW+Ij6ytU+W8j1UZeLmSEsR5K+flBaWMY= +github.com/IBM/keyprotect-go-client v0.6.0 h1:jZExoYSaoQ5TrfEzPOmBLc1vJ0VWA0RfKC+Bx39IeGo= +github.com/IBM/keyprotect-go-client v0.6.0/go.mod h1:SVr2ylV/fhSQPDiUjWirN9fsyWFCNNbt8GIT8hPJVjE= +github.com/IBM/networking-go-sdk v0.19.0 h1:oXmRZPLnL28OE7bVRJLvKB6vGYjCG58pLWAeTjVBajs= +github.com/IBM/networking-go-sdk v0.19.0/go.mod h1:nViqUm1Bv+ke8dyOhjQ6e+2U1XeqZX2y4bQbR8Od3Hc= +github.com/IBM/platform-services-go-sdk v0.19.1 h1:RDxIHiqmxQWSYrJGm4oGSvvbKg4TXY1ox53ORsX6zvE= +github.com/IBM/platform-services-go-sdk v0.19.1/go.mod h1:2pH+yjJTvL4l5Plp+uig5+U0QGwQfbBnAqu6XGPblMQ= +github.com/IBM/vpc-go-sdk v0.4.1 h1:aBjdeVW3dDry+x1B2je06Ga47FgRn9QstTjMr0RxcJY= +github.com/IBM/vpc-go-sdk v0.4.1/go.mod h1:QlPyV8sf1K4Si7CgEyAbmDonabnhJ7tC4owcjrTz3Ys= +github.com/Jeffail/gabs/v2 v2.1.0 h1:6dV9GGOjoQgzWTQEltZPXlJdFloxvIq7DwqgxMCbq30= +github.com/Jeffail/gabs/v2 v2.1.0/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OctopusDeploy/go-octopusdeploy v1.6.0 h1:r9ThVuANGkzm3noAjLF/i7LUcxQxbCJwpvn1DLwPoOA= github.com/OctopusDeploy/go-octopusdeploy v1.6.0/go.mod h1:maPbD8azyb2mcNN6E4SGrwiLN7XmDSML5ui+mcWR/R0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PaloAltoNetworks/pango v0.6.0 h1:QKe17XsICz2P1S6sKpaH1w8zr/4Q3jYsYVq7bQTjfv8= +github.com/PaloAltoNetworks/pango v0.6.0/go.mod h1:xpwEKL6CHhniRcqKYTjIiGBzPd3QIyto3sz2ynsP1qg= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/SAP/go-hdb v0.105.2 h1:ZVsCj1fMBYFfAG9ZlsA9ARmM3dv24tzotBS2ghyKY0c= +github.com/SAP/go-hdb v0.105.2/go.mod h1:+xdpA6/O3mALSp1bmn8yldN2aq1TCxZ7Ah0AuAm8B7E= +github.com/SermoDigital/jose v0.9.1 h1:atYaHPD3lPICcbK1owly3aPm0iaJGSGPi0WD4vLznv8= +github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= +github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/ajg/form v0.0.0-20160802194845-cc2954064ec9 h1:fJ4XPqxuZfm11zauw9XX7c30P8xwDyucdWu8H6Htrxs= -github.com/ajg/form v0.0.0-20160802194845-cc2954064ec9/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/gometalinter v3.0.0+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= -github.com/aliyun/alibaba-cloud-sdk-go v1.60.295 h1:oUQYOKpPm4h7shYEdPJ0T8EzVpu7Zz34qTof9XaMDxY= -github.com/aliyun/alibaba-cloud-sdk-go v1.60.295/go.mod h1:mNZkuqaeM5UCiAdkV4r+lrheu8Q5fe/487bRFrGYZ8A= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.1247 h1:2RSX5oi4GuhZnOpuW5EA6618G8mvP1X88o/4rleB5/A= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.1247/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM= github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw= +github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= -github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= +github.com/apache/openwhisk-client-go v0.0.0-20210106144548-17d556327cd3 h1:CMvrWrV6C3FOAscQwvCcRGQyQ93KLMTUXCFFS+JGgP4= +github.com/apache/openwhisk-client-go v0.0.0-20210106144548-17d556327cd3/go.mod h1:jLLKYP7+1+LFlIJW1n9U1gqeveLM1HIwa4ZHNOFxjPw= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= +github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= @@ -139,71 +183,277 @@ github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2 github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171/go.mod h1:JXY95WvQrPJQtudvNARshgWajS7jNNlM90altXIPNyI= +github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er+LKDHDUfU5tRvFwxH0LjPpZN8OoG8Ll+liGU= +github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aslakhellesoy/gox v1.0.100/go.mod h1:AJl542QsKKG96COVsv0N74HHzVQgDIQPceVUh1aeU2M= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -github.com/aws/aws-sdk-go v1.19.39/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.30.19 h1:vRwsYgbUvC25Cb3oKXTyTYk3R5n1LRVk8zbvL4inWsc= -github.com/aws/aws-sdk-go v1.30.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go-v2 v0.24.0 h1:R0lL0krk9EyTI1vmO1ycoeceGZotSzCKO51LbPGq3rU= -github.com/aws/aws-sdk-go-v2 v0.24.0/go.mod h1:2LhT7UgHOXK3UXONKI5OMgIyoQL6zTAw/jwIeX6yqzw= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk= +github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go-v2 v1.3.0/go.mod h1:hTQc/9pYq5bfFACIUY9tc/2SYWd9Vnmw+testmuQeRY= +github.com/aws/aws-sdk-go-v2 v1.3.1/go.mod h1:5SmWRTjN6uTRFNCc7rR69xHsdcUJnthmaRHGDsYhpTE= +github.com/aws/aws-sdk-go-v2 v1.3.2/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8= +github.com/aws/aws-sdk-go-v2 v1.4.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w= +github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2 v1.11.0 h1:HxyD62DyNhCfiFGUHqJ/xITD6rAjJ7Dm/2nLxLmO4Ag= +github.com/aws/aws-sdk-go-v2 v1.11.0/go.mod h1:SQfA+m2ltnu1cA0soUkj4dRSsmITiVQUJvBIZjzfPyQ= +github.com/aws/aws-sdk-go-v2/config v1.1.4 h1:2hjdDldmJJjb+rFieQySfOFt4WwxKZJVTEB6RBI74T4= +github.com/aws/aws-sdk-go-v2/config v1.1.4/go.mod h1:op05ummoVoAqctpA80jVt/+hvEtLfuKmDyx0bIuvfbE= +github.com/aws/aws-sdk-go-v2/credentials v1.1.4 h1:whYYw2srG+zUQzUw4LhML83f+xd22Vm7gv0I7aJglc8= +github.com/aws/aws-sdk-go-v2/credentials v1.1.4/go.mod h1:UQwsT2w2XelrWoVV2v/zL2uce1RxmVCiHaZsoKLamZg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.5 h1:5gCrezE41xYQHWDsDkJD9nT22tUH3s+Zrvs4c3v2FGc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.5/go.mod h1:z/NKNlYxMzphl7TzjV+ctUebHF4CFNGGlSvmV/NKcJU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.0 h1:zY8cNmbBXt3pzjgWgdIbzpQ6qxoCwt+Nx9JbrAf2mbY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.0/go.mod h1:NO3Q5ZTTQtO2xIg2+xTXYDiT7knSejfeDm7WGDaOo0U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.0 h1:Z3aR/OXBnkYK9zXkNkfitHX6SmUBzSsx8VMHbH4Lvhw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.0/go.mod h1:anlUzBoEWglcUxUQwZA7HQOEVEnQALVZsizAapB2hq8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 h1:d95cddM3yTm4qffj3P6EnP+TzX1SSkWaQypXSgT/hpA= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.2.0 h1:G7NSCbvUWDp4B0ny7tjHfuZvadphb7M66/1cYN9AnAg= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.2.0/go.mod h1:PMYdnRge1BUXxlvWhynvcT7ltjXevZ/pVV56B299wT0= +github.com/aws/aws-sdk-go-v2/service/acm v1.2.1 h1:s3Yka4ZE67lTTbSG7ZXlgwIjC122RkG6okTcrEbCBBY= +github.com/aws/aws-sdk-go-v2/service/acm v1.2.1/go.mod h1:X6p3MQnaIMOJ6+A1D7OfW3WKt7rJzgZzSeVkua6lZrg= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.2.1 h1:2kxNxcT9QVSckqagWevdNOAOCOAmGHsCbkowF6Rmur8= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.2.1/go.mod h1:4fO3jaFTaz/8ygZBVNSk4NSdAwcc/NZ++HUrG9kpJ0I= +github.com/aws/aws-sdk-go-v2/service/appsync v1.2.1 h1:qHxx2jl6nI6Sn5fuXtBQVWbhaG+fErDAB47BHm+Kw1A= +github.com/aws/aws-sdk-go-v2/service/appsync v1.2.1/go.mod h1:JkdNL71yKS0qmF+dFJJzxf1WJZWFGIhTepXHaxtKipE= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.3.1 h1:fQkypDE1Ll/W61tm8GoswgLjWfO8y1f50yXw5lA4uFo= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.3.1/go.mod h1:DVmOqpa3F7vhAuGfs2zse1f3N3mX64hCimRNSYiqnKE= +github.com/aws/aws-sdk-go-v2/service/batch v1.3.1 h1:dZSRS8i4wL+lB87FCCHBynaD7BgrYyESuEzmx23/pOg= +github.com/aws/aws-sdk-go-v2/service/batch v1.3.1/go.mod h1:sx7fSwDOWJhJ9Z/+SCHfisxlIXmPXqovaksLqQy/+w0= +github.com/aws/aws-sdk-go-v2/service/budgets v1.1.3 h1:P2IXGUpF2t6gwy3QTPB82/wFarHkX6WVsHWs7nfaVWY= +github.com/aws/aws-sdk-go-v2/service/budgets v1.1.3/go.mod h1:1NXNu5eiAZbLx6bK0Ir2X4MBXBO6JSMaPN3mdRaYZqo= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.1.3 h1:I2V5IX5pwXq/+TL5QeDcoq4MIcFgzQ/yxbf5KTEqm4Q= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.1.3/go.mod h1:bT6aHBpfi2TFnyOvBe3IjZkI7cXYaZ0uEErZE1bMABM= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.3.0 h1:+eHZIcEQ7jMuAAWL9uS9RfQz8ElLcRksWqXSIQ7essE= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.3.0/go.mod h1:9PLAEZCkzDVh+/fq7OwOloe/RqSpqwes2x+ozcRyloM= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.3.0 h1:8fOeCj6bb2JtkWvxP6McS4RR/CV20IG4JzZWYz4Z12E= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.3.0/go.mod h1:J04vwlb6n/oVJNtNyT+sLx2KDgzyo7nDRyHPnnZQYnk= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.1.3 h1:otg0eUT5LROwUixNpOtjhYksgBurDIRi6ykUmsBBrA8= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.1.3/go.mod h1:mtJg2sJe7X8jm/cL/OIxJkPPPGQbHNgQnipZgN6a4MU= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.2.1 h1:egAyiJ8xpfed+I+8t+71OxyNr4Vbw1xRA+9EjSu15tU= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.2.1/go.mod h1:GtzMwrY6i7/RXMKBZAMXyXFmZ1UHxtxDeIiUO3lBXRI= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.3.0 h1:fyDRD5nYw4WlTQpX7p5MjtKX1SkEs5pLHt0bt7Zn0/A= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.3.0/go.mod h1:2qNhOhvtzQHNKkwipEb/n95O4pAfJy4ObXv0n+Ldkn8= +github.com/aws/aws-sdk-go-v2/service/cloudwatchevents v1.2.0 h1:gXHyajuXD6lC4iaznrJcFzxOyg0E7f94MpRKmJ4hwvU= +github.com/aws/aws-sdk-go-v2/service/cloudwatchevents v1.2.0/go.mod h1:oqhgyu/GPZZpma8mHoiUhqSwx2gSlxjccE9Lny3RR2g= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.2.3 h1:Nndr+JIWrHV7VZOYPvRfI0teEDxRXQuZ/IsPalo8Zg0= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.2.3/go.mod h1:SMDBeigW7S6RmOMSAwbukEb5JM5WHwUOvNOzZXDXRR4= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.2.1 h1:Kn8KgAStqC7/FMP927qsWUUQJH9gw/ubKTuMqyKUpds= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.2.1/go.mod h1:n5wJZmnZAZxSQDf7CnNpyTCOP9cjTGsmH1xkCs8Giy4= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.1.3 h1:Fw5BXP0L4PNdneYOv0B2znzErlgj70QNEc7HIjwJrUs= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.1.3/go.mod h1:8RUQJoX54ROI44zDHSk5sIoyyBaYmy2bdBv7XZmcpp0= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.2.1 h1:WEqfKQLKriwX7BQyUXfJzK/gO6wMelZxtwOHD2cyjeg= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.2.1/go.mod h1:yLCnpa5QV9tRDM7Hl+2sMgOsL1+Od9L/i9EmRUxBK5s= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.2.1 h1:rFLNwNLEB+1wvueAOwTmuGS2WM4tc4Ly9vidfA6642Q= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.2.1/go.mod h1:FQdcXAJhwsXv9IqpIQYw4FjpTtdUv/CMjQ/C54HuyIs= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.2.1 h1:SxtoHbLsxtdUMeKD3Gdd1hCxkXlT1s2qok/k4S9arbY= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.2.1/go.mod h1:uSWFf65jWgwb/QH4TlkQX4t6CL4jNEtJPFtGfC7fPb4= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.2.1 h1:fEO/gs2CUMpBAoOTuLRnaMGhKCgntz6ZYvmXDDY/nOc= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.2.1/go.mod h1:cv/vtBmaOXXxLctr2OdeDWGJAJiNJ3Ilh3VKi4NAiAA= +github.com/aws/aws-sdk-go-v2/service/configservice v1.3.0 h1:F1VtAhAtPq6TxgRlBlpG4dF2BG+udfvFEiuOMSBG6Jo= +github.com/aws/aws-sdk-go-v2/service/configservice v1.3.0/go.mod h1:iUPe1LAYqj8xaouHcns/bNEIcryZ7uuXVbcgj0SyT/k= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.1.3 h1:dF5BSnxQIaFmpNbi7ybcP76Aa2ODKiA2WKjXsa/tTKU= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.1.3/go.mod h1:KfO/6uA+14FbbKydAiDSRKYG+DwEhYr56ujLlCgJCnw= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.1.3 h1:6y0p4RYpzNH6B8dlbNXfVyMl55EQHvJAXw33OLffA7o= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.1.3/go.mod h1:0sLAFkQrOqjK9Nm9CtrAB36cBQGe8K/1PsFHVPiZbvI= +github.com/aws/aws-sdk-go-v2/service/docdb v1.9.0 h1:riGho+STq0uon87fxZGltLVJ3H+0G7SwdWgNGEZJc2M= +github.com/aws/aws-sdk-go-v2/service/docdb v1.9.0/go.mod h1:1DCw0WdpubCl2OLsJbkol6phbHycCEcD5jGxbNUg6Kg= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.2.1 h1:NnYXRukLvkiTnNyZHCCQcZaoWJSeE5Y7tCVPgvTyWfw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.2.1/go.mod h1:WqAbIrpO0PSa3AIDxMG12aPPN4D1u99rOFdEfSM/KgY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.3.0 h1:y82WbYudKuiWx0KuKQheqTQ4RIF8ZHoHvS/rD8HCYCc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.3.0/go.mod h1:KW2/Fgs+L1m1X53O9hTFpJqPtLyYGbf9j1Ay5xPSy74= +github.com/aws/aws-sdk-go-v2/service/ecr v1.2.1 h1:rdvoJaE51N1tuNc2B75vNsZu2P0xV6y7ibOAwNeb1mI= +github.com/aws/aws-sdk-go-v2/service/ecr v1.2.1/go.mod h1:iuqVazSEO7GWaX6WYrVWCVECL3ixXwhL6Q6RF4V2Db0= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.2.0 h1:Qb0q2R4dff4/e/qvSVPyTs3ZME+zlzN8HDCm0+F1Ko0= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.2.0/go.mod h1:njYzwMTk1bscTUcF56dR9DO5ORsVaV6FMQC+/wZNGjU= +github.com/aws/aws-sdk-go-v2/service/ecs v1.2.1 h1:T8CKZFKySyOivXUc/80qlvNqvX9MQvvRCxFQCL6xxQU= +github.com/aws/aws-sdk-go-v2/service/ecs v1.2.1/go.mod h1:7gzy9DNs3NWZnxJcV61X0EjhLzDuZm8uUA+moRIoiKs= +github.com/aws/aws-sdk-go-v2/service/efs v1.2.1 h1:Cm/7OSlvQVPQpksrq7FYXw75Uv1D8++CA6tcWMb6y38= +github.com/aws/aws-sdk-go-v2/service/efs v1.2.1/go.mod h1:4UVgbo/4cTvbn0Y+lU+Sq7gvNlY0zPbmn1JCqkGiyHs= +github.com/aws/aws-sdk-go-v2/service/eks v1.2.1 h1:eNSGiZZKcrjT1/UlxOSL/v1gjR5bePJk4xMdGBZXd1o= +github.com/aws/aws-sdk-go-v2/service/eks v1.2.1/go.mod h1:XGNXr+eBGsXebPMHCHHJEaOWaenvyybnUU+dsdKpDXg= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.2.1 h1:r2GU9mRLlZtKNQiB8A6LeKMlxG0BK/LXU+86uv3zUos= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.2.1/go.mod h1:H/CnUlHdpSJ6bi4PTZn7H046nY+OF0O1ItZGpOHbZ1s= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.2.1 h1:ngD2ETQ+bmpE9dXIwpovAKfEqhK0SODf0EQDMY7qkMA= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.2.1/go.mod h1:h2ETsoGWjnQFCsd5aYeg6+sf/HqLo7Qr7OKjSe4Axs4= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.2.1 h1:jN/we+fXuZeye2ZIPAGCI8xV6MT/JiT1JnpRUgkmG2M= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.2.1/go.mod h1:2J/pAuvfB8TQHdrbVX3t4Udjv6Cd2JohqGnoMZHKhe0= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.2.1 h1:4fbYf4lBHxmT0r48Ll7+Ls7e68jFdAgGs/JFXYeUiJA= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.2.1/go.mod h1:SGDkclfP0NWhrOMlh6IUPKUWooGcfNP2bR1O58+SZSM= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.2.1 h1:abdGxf1AJqZJTKAV7b7RKlwG5tdB82tqcUrd4JCRop0= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.2.1/go.mod h1:OflbS5dnlP5cKuSTJUR4MEF/02a7yg5t6MjxhyyAPiQ= +github.com/aws/aws-sdk-go-v2/service/emr v1.2.1 h1:YHcDnfSGq/DfLqIU+qf1uZ3tXVr5kythLVet2zWQZFY= +github.com/aws/aws-sdk-go-v2/service/emr v1.2.1/go.mod h1:cAGYVhsN+3rqjZb0TO8FaNtfV++ItE3vWiqzQTAkQ1Q= +github.com/aws/aws-sdk-go-v2/service/firehose v1.2.1 h1:XG4P2vpReYdY920Pf0pze6O7h7SFUkyIRVNYHNWtA2Y= +github.com/aws/aws-sdk-go-v2/service/firehose v1.2.1/go.mod h1:Zt1lhxCqEWgjYOtpQp1zNg+KGz5GBrJ3Kh2CY3tuAM0= +github.com/aws/aws-sdk-go-v2/service/glue v1.3.0 h1:xnSuV0C7FGfe9+/GJ/2KOTFD3WMXtLdk8gZzxuuuIRM= +github.com/aws/aws-sdk-go-v2/service/glue v1.3.0/go.mod h1:ITzMOyWhffmh06X4DxvN85ww8Ppt0uZGh8Qcty22/yQ= +github.com/aws/aws-sdk-go-v2/service/iam v1.3.0 h1:V95YLxbxLGlTcFR0KMMSZEaudIxYCAhycSGcO7/Favs= +github.com/aws/aws-sdk-go-v2/service/iam v1.3.0/go.mod h1:gPUYT7MBEb30j9eAsJ17LN9KbXtD1uqKOOKesCC4tjc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.3 h1:iLFz4nrWkXMTFeVn0n99wRyc4Xib4SlDbtAM3h2z8P8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.3/go.mod h1:g3Xw4tO/W+ae4EMzkxB6nGnJ48cLM4i1Z61WmD+IKtY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.5/go.mod h1:MW0O/RpmVpS6MWKn6W03XEJmqXlG7+d3iaYLzkd2fAc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.0 h1:qGZWS/WgiFY+Zgad2u0gwBHpJxz6Ne401JE7iQI1nKs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.0/go.mod h1:Mq6AEc+oEjCUlBuLiK5YwW4shSOAKCQ3tXN0sQeYoBA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.1 h1:wCzfVBrF1QRQFacZn1ywE/o2p92FzfpDNI2aCpIv+sY= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.1/go.mod h1:6A0VfJAnYwhcXzt7KsixOdFlITEH5NFl4QeYxlZ5TtQ= +github.com/aws/aws-sdk-go-v2/service/iot v1.2.0 h1:OTrzh5ew69Vd6x1zruCQ7B/dtcxwCQ5ohPJWwfkydKQ= +github.com/aws/aws-sdk-go-v2/service/iot v1.2.0/go.mod h1:YzUfLvXlWGDMednNccsykrwSJmVGy0YeD+XwH8nRcIg= +github.com/aws/aws-sdk-go-v2/service/kafka v1.2.1 h1:70IRtg4hU1mQ5aAtjEHPQR+KCeVIDwLOpvbofiSEODE= +github.com/aws/aws-sdk-go-v2/service/kafka v1.2.1/go.mod h1:2gy+VDVpxUvxQRdjpFlZNhXSjybrxnYrb9Byuzz855I= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.2.1 h1:MXy6AyLlbBYypXEsmK94l9yGjKKtxNaD/jFzVVOsnYQ= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.2.1/go.mod h1:ZdVDeEkxSDTPYDtb8kVxXzyOSBkAQVXCA9fanM45a/c= +github.com/aws/aws-sdk-go-v2/service/kms v1.2.2 h1:9CJBrElBVX699f4ugbwsD2EPyHYWEdf9rGZZJwDzPSU= +github.com/aws/aws-sdk-go-v2/service/kms v1.2.2/go.mod h1:aDkYNnoS4NikbSA7AiTomko1eJIZgrIG0ZE0yPJRn+w= +github.com/aws/aws-sdk-go-v2/service/lambda v1.2.1 h1:U1AhnZgIHWCh6kIXuq6RkTptzU6szpDHjRbrA7g+99s= +github.com/aws/aws-sdk-go-v2/service/lambda v1.2.1/go.mod h1:lczLef9EKYeQQ23eksYHU/Qf8j+66FSlX+g+15ZEP+k= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.2.1 h1:/NgTgipY3ADAqLp18q1dDomqHYULUrcD3v3XGdqIhT8= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.2.1/go.mod h1:S3JR8Z73bcaBwD1ddXzMcEkR1FFptmmY9pbsmCVWfn0= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.1.4 h1:7ho72LnawdmIm8J8KdkLoLWgcsqLcS8oKBDuT3005wg= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.1.4/go.mod h1:kXoBJPOMmUdpMEqWUhEPolBoycGzLGUHS5a/mL1+y1k= +github.com/aws/aws-sdk-go-v2/service/opsworks v1.2.2 h1:CMif3Cy79NfLPcYuyYidNdynqeEZCK0i2LTPKB4sMQQ= +github.com/aws/aws-sdk-go-v2/service/opsworks v1.2.2/go.mod h1:elwiAmL4KdGNzNE5HjyxgKBoj7pjOhyOof0KGciJRAg= +github.com/aws/aws-sdk-go-v2/service/organizations v1.2.1 h1:TvDVD1mBXP60NIHrqbP8uuzTf4vu48HlOm5jtoQQcW0= +github.com/aws/aws-sdk-go-v2/service/organizations v1.2.1/go.mod h1:iy7PhC7Wxk3aRePrvaUU7ngXjcAedbTBeKYAYVhnvfI= +github.com/aws/aws-sdk-go-v2/service/qldb v1.1.3 h1:mQUBlaWu2q7RftA5O8psLn2wQTIJAQEX0eIp3dZOtxQ= +github.com/aws/aws-sdk-go-v2/service/qldb v1.1.3/go.mod h1:PgBTgxJV+wffbLmlJB/zO0/lD8+mEbUzEK0LvPkbxXM= +github.com/aws/aws-sdk-go-v2/service/rds v1.11.0 h1:sFjF9JiGSFnBrcXgOM3Fm95SSOrAMywiyTb1bjO0oTE= +github.com/aws/aws-sdk-go-v2/service/rds v1.11.0/go.mod h1:CD31RSZUKoDEo7ZewGGutgOeqZvlZ4v8Skoyeizjt/o= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.2.1 h1:36JI8JwGQEH5JcRXdpWucey2jr+mSLZWEvLWZLo73PI= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.2.1/go.mod h1:fS4Gj1TYWWpQB0qHsijLygpI6zUFkEwoHSf8ajXFTqQ= +github.com/aws/aws-sdk-go-v2/service/route53 v1.3.0 h1:uwKwx0iSdZyIwQmsMPtAoBjlRC1lFUAhx2c6HGWjfPM= +github.com/aws/aws-sdk-go-v2/service/route53 v1.3.0/go.mod h1:vwPNxNmptQ70lgw8W4EzuHKCygDpVvhjJ/Xri8cnF80= +github.com/aws/aws-sdk-go-v2/service/s3 v1.4.0 h1:045tK3IL+TxOSWWQyG199A0BYJ/Yhgk8XV9xo+nQkLQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.4.0/go.mod h1:zFD4go1gW0I/WxeGfCNSsz/BnZSJyu5arLPMPnw0gvQ= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.2.1 h1:g5UomfutRdIkbsqdGr4XyuVyTZM+sp7ySmnoU8zai9s= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.2.1/go.mod h1:5UqHs6oUHhBRimgTAWZJ1uXa+A8QFLbOCi5yRZxLQAs= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.2.1 h1:qZplAHGJFl16wbZAWEnP73dzATdJDBly6ccPfeSeffc= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.2.1/go.mod h1:SI3V2iXBWczkoetsurbZjbTNv2rCJihbo5APtlDLbCQ= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.2.1 h1:/FTF3YGI/WxRnRKhruU1nyhR/gzgfYP0kQF7yIaqEjU= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.2.1/go.mod h1:bivtoAQvh328aJFiY3+h4lQpyv9kPjJAP/y/PCQbnVY= +github.com/aws/aws-sdk-go-v2/service/ses v1.2.1 h1:hHtrVZvqyYzXYzMyZb6ww8aOI7n3X61uughtdJ8v8E8= +github.com/aws/aws-sdk-go-v2/service/ses v1.2.1/go.mod h1:l6zMRkVtC7WmAxDPRo/WwHSu+TXTKITQDPse/OgoViY= +github.com/aws/aws-sdk-go-v2/service/sfn v1.2.1 h1:L9eiomAn2X5JnUbJs//EbLmbQAOwFIjxowjFTb1+mg0= +github.com/aws/aws-sdk-go-v2/service/sfn v1.2.1/go.mod h1:E0SrMJis5ShsOfbc+WIpmn9sr7IbJV6puIBaWipvadE= +github.com/aws/aws-sdk-go-v2/service/sns v1.2.1 h1:IVHrunoAsIp1OV445PE84mM+WArZChXrxNbFIx4uAWQ= +github.com/aws/aws-sdk-go-v2/service/sns v1.2.1/go.mod h1:23FVJ4I/AHqbkh4vMa1Cz6/vXMCuMLPkU9Pi4RCFgxk= +github.com/aws/aws-sdk-go-v2/service/sqs v1.3.0 h1:iePzn4Gr4p5QKat3G7snhUvopc/lOj25ZiPJ4/PPzq8= +github.com/aws/aws-sdk-go-v2/service/sqs v1.3.0/go.mod h1:9bo6m/Pes+TR6ORT97E1BkczbSgbpKB1qTyFt08s9yw= +github.com/aws/aws-sdk-go-v2/service/ssm v1.3.0 h1:0swJm4MqIjN1v1tM9GQ8hGv+KXv4smEiftpAXg84aZg= +github.com/aws/aws-sdk-go-v2/service/ssm v1.3.0/go.mod h1:WX5OhauvURAo0+ljp29uEIitBkt3+Y3RGnVa9ix2xc8= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.4 h1:Tr/SsFDXWN8rntdzTNrDs/MvuBXRCjY6xvJrPFUPKRM= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.4/go.mod h1:yQayEbOWH75NaKFylsFocBc3yanYEGndlOaH4i/Lvno= +github.com/aws/aws-sdk-go-v2/service/sts v1.2.1 h1:1koRvKlZMN+FhTGV5f4q6vRHXNJzeZlPKzbs1/Y32Kg= +github.com/aws/aws-sdk-go-v2/service/sts v1.2.1/go.mod h1:L1LH5nHMXxdkKj057ZUx7Wi50CCrkZ+9jkTnBnY2j/w= +github.com/aws/aws-sdk-go-v2/service/swf v1.2.2 h1:DPm8xVttctfEAALcJArYJxmI4SObDIftsipl4ykhF0E= +github.com/aws/aws-sdk-go-v2/service/swf v1.2.2/go.mod h1:JiYj3t717Tna1ylyqV8KZZq3yPdvt0693LvytZ8OKeI= +github.com/aws/aws-sdk-go-v2/service/waf v1.1.4 h1:Wh0YMwF394A9eBC8Pv8Uxk6CBx9KTWmoqyflQIBx6DU= +github.com/aws/aws-sdk-go-v2/service/waf v1.1.4/go.mod h1:Ujifac0yyu5RLw3cPCGua50uHnsjiJo9LAhXEJZ+tVk= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.2.1 h1:Re8Uwffnndo9t8V46kT3aruMvVXHXUmuYKhIF1U9CBc= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.2.1/go.mod h1:WvRSWmA7SJw0TbU0XKCo+oC/qsD/OR/tFRzTnq8FBpk= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.2.1 h1:hSzpp50D6D37eIELSSpYwJ75e8XL9bvTzjspZgt4+5A= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.2.1/go.mod h1:8k9EEz8LMNPUDENPlW0laaQkAZC2TbEYF+XNUu1lFLk= +github.com/aws/aws-sdk-go-v2/service/xray v1.2.1 h1:RiTWbH90tIuJNnZZys9HeqBfpT3oSPulh7fM7anPQiY= +github.com/aws/aws-sdk-go-v2/service/xray v1.2.1/go.mod h1:MZS769M8/1Xm4XYQydDJbvugo7dG8fXzsVU3J84QXzY= +github.com/aws/smithy-go v1.2.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.3.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.9.0 h1:c7FUdEqrQA1/UVKKCNDFQPNKGp4FQg3YW4Ck5SLTG58= +github.com/aws/smithy-go v1.9.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk= github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/bsm/go-vlq v0.0.0-20150828105119-ec6e8d4f5f4e/go.mod h1:N+BjUcTjSxc2mtRGSCPsat1kze3CUtvJN3/jTXlp29k= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.13.5 h1:28S2iEUK67exPyt/IkmAIFbDAVjyKU1cYzrURj5k84s= -github.com/cloudflare/cloudflare-go v0.13.5/go.mod h1:OgJ1r3tslnIyWr7kX2OCBKUbSnUIyFKEIlZex9qgmIo= +github.com/cloudflare/cloudflare-go v0.13.6 h1:G6aw092fOkvkHODCxf8EHLPqHN2BVxHU4RoTFjS51xo= +github.com/cloudflare/cloudflare-go v0.13.6/go.mod h1:gNGW6MkPPVLhjgaXq4vaS7WnTaQpCfl6DE1W9JuWyt8= +github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= +github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cucumber/gherkin-go/v13 v13.0.0 h1:d09AwPZldyOFlCADAIZQMt7T+VHCrGdp5106+BCIfZU= -github.com/cucumber/gherkin-go/v13 v13.0.0/go.mod h1:pzMEPEIPcPOBDkE8HaWC+Ck6eDBtBmIWVksUkSin/2E= -github.com/cucumber/messages-go/v12 v12.0.0 h1:ZlZYZrYDDc35zCe0HK2y95GUcxHHqr8yB9kdrXCjnzU= -github.com/cucumber/messages-go/v12 v12.0.0/go.mod h1:5zuJu21U6rB+BBqyGoQr839a4h4GUElPnSozdHyhCOQ= +github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRvYMqLQeR4DHyTvs6y0MEMymTz4vyFpFkKTPs= +github.com/crewjam/saml v0.4.5 h1:H9u+6CZAESUKHxMyxUbVn0IawYvKZn4nt3d4ccV4O/M= +github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S68bk= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidrjenni/reftools v0.0.0-20191222082827-65925cf01315/go.mod h1:QXiCu8WKyFL/X+NMCmtxoCq/jSOb54R4iDXdjsaYEWA= -github.com/ddelnano/terraform-provider-mikrotik v0.0.0-20200501162830-a217572b326c h1:/y0rm2Eg2xe4/qkZp7jNrg/hhAt9AEPjwuimkTY6938= -github.com/ddelnano/terraform-provider-mikrotik v0.0.0-20200501162830-a217572b326c/go.mod h1:GfNYCa+c8fEK3kDRjxMeQiEdPyeORDK8Zi7ykJBA0/w= +github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= +github.com/ddelnano/terraform-provider-mikrotik/client v0.0.0-20210401060029-7f652169b2c4 h1:AMuZg5VR0/QGCqFpO4CUwAhZc4tbgDHpM8c4SvMt2yM= +github.com/ddelnano/terraform-provider-mikrotik/client v0.0.0-20210401060029-7f652169b2c4/go.mod h1:JrRtRlTHCkdIr7OTHCAonKS2yWwmwdqnvf+JEy+OYAA= +github.com/ddelnano/terraform-provider-xenorchestra/client v0.0.0-20210401070256-0d721c6762ef h1:q/XC0MjIz8cl/NtyKKewDns6mNd2cUzLQ5Xnh+jGoRg= +github.com/ddelnano/terraform-provider-xenorchestra/client v0.0.0-20210401070256-0d721c6762ef/go.mod h1:1T10mQuoIeT4CXsvyc1G1m/+L7mWv6p7cBwmAut/uB0= +github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= +github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denverdino/aliyungo v0.0.0-20200327235253-d59c209c7e93 h1:ujQ4DKs+MqFWy/hoLAU4Ey/nQhqJ6pXyocMDbVJ4qSw= github.com/denverdino/aliyungo v0.0.0-20200327235253-d59c209c7e93/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dghubble/sling v1.1.0 h1:DLu20Bq2qsB9cI5Hldaxj+TMPEaPpPE8IR2kvD22Atg= @@ -211,45 +461,60 @@ github.com/dghubble/sling v1.1.0/go.mod h1:ZcPRuLm0qrcULW2gOrjXrAWgf76sahqSyxXyV github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.35.1 h1:3P5timR4LTqcCafzrCgV2j83ck4aWb937ybFC7YQVFw= -github.com/digitalocean/godo v1.35.1/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= +github.com/digitalocean/godo v1.57.0 h1:uCpe0sRIZ/sJWxWDsJyBPBjUfSvxop+WHkHiSf+tjjM= +github.com/digitalocean/godo v1.57.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dollarshaveclub/new-relic-synthetics-go v0.0.0-20170605224734-4dc3dd6ae884 h1:Od9CDqwkw5F3vjN8Lp8CQhkMOEjC70eTW+AJlTepE6g= github.com/dollarshaveclub/new-relic-synthetics-go v0.0.0-20170605224734-4dc3dd6ae884/go.mod h1:SB2lZXXkyipTEoPLxR3A5YglkZ7QwoXSsyI9h6yUeFc= +github.com/duosecurity/duo_api_golang v0.0.0-20201112143038-0e07e9f869e3 h1:7/i/g2rlBeX1DHg5xTrR2hiFi87ZrqRWV3eLZUApjdI= +github.com/duosecurity/duo_api_golang v0.0.0-20201112143038-0e07e9f869e3/go.mod h1:jdoEJUIrTIxN7nNTwwqA3TBNcSM+W1lrWM6OXVhjbG8= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1/go.mod h1:lcy9/2gH1jn/VCLouHA6tOEwLoNVd4GW6zhuKLmHC2Y= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= +github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fastly/go-fastly v1.15.0 h1:t7f0ZnQy0rKYN8FCql4wHkfZNHajxDs1hT/phazOpp8= -github.com/fastly/go-fastly v1.15.0/go.mod h1:jILbTQnU/K/7XHQNzQWd1O7hbXIcp6dKrxfRWqU6xfk= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fastly/go-fastly/v5 v5.1.2 h1:QzOc35dfeoMlNgTkbHBGCiwkfnZzDBDptH3/zTqh80Q= +github.com/fastly/go-fastly/v5 v5.1.2/go.mod h1:4WKmXkCyvjq6+XlE9zrCBsFyoQngQGQjVkpr0LjAXoY= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/gomodifytags v1.4.0/go.mod h1:I1Y8xh3aVI37vceIxNEr549I/TnDN1wuVPZM7NUR7kA= -github.com/fatih/motion v1.1.0/go.mod h1:go/hyCtg5rx6FjoC0o+iInMzlY2u7OeHayKYDY6Gbmk= -github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/form3tech-oss/jwt-go v3.2.1+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-bdd/assert v0.0.0-20190820124234-20d47a68475d h1:zQazu3kApPoajWmXj9zFpCNE+UDefwwFRijKjzvHNCM= -github.com/go-bdd/assert v0.0.0-20190820124234-20d47a68475d/go.mod h1:dOoqt7g2I/fpR7/Pyz0P19J3xjDj5lsHn3v9EaFLRjM= -github.com/go-bdd/gobdd v1.1.2-0.20200703080921-409b71954655 h1:hKQ7ba/nVgQ0sGq8KBWJ7hdm0CEN48AlIYjBmfzCQzQ= -github.com/go-bdd/gobdd v1.1.2-0.20200703080921-409b71954655/go.mod h1:Q3mXpW/Qm9GJCPLxFCTXdTtRBdHzcTfrbeLlaqAPtXM= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -257,37 +522,84 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.8 h1:doM+tQdZbUm9gydV9yR+iQNmztbjj7I3sW4sIcAwIzc= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.10/go.mod h1:qBBipho+3EoIqn6YDI+4RnQEtj6jT/IdKm+PAlXxSUc= +github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= +github.com/go-openapi/strfmt v0.20.1 h1:1VgxvehFne1mbChGeCmZ5pc0LxUf6yaACVSIYAR91Xc= +github.com/go-openapi/strfmt v0.20.1/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-resty/resty/v2 v2.1.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 h1:JVrqSeQfdhYRFk24TvhTZWU0q8lfCojxZQFi3Ou7+uY= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= -github.com/go-routeros/routeros v0.0.0-20190719172022-0819accf8221 h1:HJ7/f/eGwr7jlZl0lsnNT38/mKcSluFGTc5uLHn4pwI= -github.com/go-routeros/routeros v0.0.0-20190719172022-0819accf8221/go.mod h1:em1mEqFKnoeQuQP9Sg7i26yaW8o05WwcNj7yLhrXxSQ= +github.com/go-routeros/routeros v0.0.0-20210123142807-2a44d57c6730 h1:EuqwWLv/LPPjhvFqkeD2bz+FOlvw2DjvDI7vK8GVeyY= +github.com/go-routeros/routeros v0.0.0-20210123142807-2a44d57c6730/go.mod h1:em1mEqFKnoeQuQP9Sg7i26yaW8o05WwcNj7yLhrXxSQ= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA= +github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gocql/gocql v0.0.0-20210707082121-9a3953d1826d h1:k544nNVphXK4Yt0FTduvOvCfJabEY/DMkdNw0zpCwBE= +github.com/gocql/gocql v0.0.0-20210707082121-9a3953d1826d/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -299,18 +611,15 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -318,37 +627,42 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v25 v25.1.3 h1:Ht4YIQgUh4l4lc80fvGnw60khXysXvlgPxPP8uJG3EA= -github.com/google/go-github/v25 v25.1.3/go.mod h1:6z5pC69qHtrPJ0sXPsj4BLnd82b+r6sLB7qcBoRZqpw= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v35 v35.1.0 h1:KkwZnKWQ/0YryvXjZlCN/3EGRJNp6VCZPKo+RG9mG28= +github.com/google/go-github/v35 v35.1.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/jsonapi v0.0.0-20170708005851-46d3ced04344 h1:G5TmuUtIYeR0scfa8ZQ06cfHeAAfVeFlIG8TVOCfuAA= -github.com/google/jsonapi v0.0.0-20170708005851-46d3ced04344/go.mod h1:XSx4m2SziAqk9DXY9nz659easTq4q6TyrpYd9tHSm0g= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/jsonapi v0.0.0-20201022225600-f822737867f6 h1:nVbdADVJLcaOp/CAR9xhaMCZrYn07HFFhUtM+dHsAIc= +github.com/google/jsonapi v0.0.0-20201022225600-f822737867f6/go.mod h1:XSx4m2SziAqk9DXY9nz659easTq4q6TyrpYd9tHSm0g= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -359,37 +673,46 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.13.0 h1:1XkslZZRm6Ks0bLup+hBNth+KQf+0JA1UeoB7YKw9E8= -github.com/gophercloud/gophercloud v0.13.0/go.mod h1:VX0Ibx85B60B5XOrZr6kaNwrmPUzcmMpwxvQ1WQIIWM= +github.com/gophercloud/gophercloud v0.17.0 h1:BgVw0saxyeHWH5us/SQe1ltp0GRnytjmOLXDA8pO77E= +github.com/gophercloud/gophercloud v0.17.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/grafana-api-golang-client v0.0.0-20210218192924-9ccd2365d2a6 h1:jFAfnEad6JNc0EFbCGxL75m8GoBG/J7/1fAAXseaIf8= +github.com/grafana/grafana-api-golang-client v0.0.0-20210218192924-9ccd2365d2a6/go.mod h1:jFjwT3lvwl4JKqCw3guRJvlQ1/fmhER1h3Zgix3z7jw= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/aws-sdk-go-base v0.4.0/go.mod h1:eRhlz3c4nhqxFZJAahJEFL7gh6Jyj5rQmQc7F9eHFyQ= github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= -github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-azure-helpers v0.10.0 h1:KhjDnQhCqEMKlt4yH00MCevJQPJ6LkHFdSveXINO6vE= @@ -397,135 +720,191 @@ github.com/hashicorp/go-azure-helpers v0.10.0/go.mod h1:YuAtHxm2v74s+IjQwUG88dHB github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.0.0-20170211013415-3573b8b52aa7/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= -github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8= github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= +github.com/hashicorp/go-getter v1.5.3 h1:NF5+zOlQegim+w/EUhSLh6QhXHmZMEeHLQzllkQ3ROU= +github.com/hashicorp/go-getter v1.5.3/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8= +github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= +github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= +github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo= +github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-tfe v0.8.1/go.mod h1:XAV72S4O1iP8BDaqiaPLmL2B4EE6almocnOn8E8stHc= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= +github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= -github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= -github.com/hashicorp/hcl2 v0.0.0-20190821123243-0c888d1241f6/go.mod h1:Cxv+IJLuBiEhQ7pBYGEuORa0nr4U994pE8mYLuFd7v0= -github.com/hashicorp/hcl2 v0.0.0-20190909202536-66c59f909e25/go.mod h1:Cxv+IJLuBiEhQ7pBYGEuORa0nr4U994pE8mYLuFd7v0= +github.com/hashicorp/hcl/v2 v2.8.2 h1:wmFle3D1vu0okesm8BTLVDyJ6/OL9DCLUwn0b2OptiY= +github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= +github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI= github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= -github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 h1:T1Q6ag9tCwun16AW+XK3tAql24P4uTGUMIn1/92WsQQ= -github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= -github.com/hashicorp/terraform v0.12.29 h1:UkuApT6qh6KONIT1Jz7HoV8f4B+x71db3bmGcBzjBB0= -github.com/hashicorp/terraform v0.12.29/go.mod h1:CBxNAiTW0pLap44/3GU4j7cYE2bMhkKZNlHPcr4P55U= -github.com/hashicorp/terraform-config-inspect v0.0.0-20190821133035-82a99dc22ef4/go.mod h1:JDmizlhaP5P0rYTTZB0reDMefAiJyfWPEtugV4in1oI= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/terraform v0.12.31 h1:df2bOxAOaR2r8kDfkqNlNk4anH2DjkPwJ4K7mEwUd9M= +github.com/hashicorp/terraform v0.12.31/go.mod h1:CBxNAiTW0pLap44/3GU4j7cYE2bMhkKZNlHPcr4P55U= github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 h1:Pc5TCv9mbxFN6UVX0LH6CpQrdTM5YjbVI2w15237Pjk= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= -github.com/hashicorp/terraform-plugin-sdk v1.0.0/go.mod h1:NuwtLpEpPsFaKJPJNGtMcn9vlhe6Ofe+Y6NqXhJgV2M= +github.com/hashicorp/terraform-exec v0.14.0/go.mod h1:qrAASDq28KZiMPDnQ02sFS9udcqEkRly002EA2izXTA= +github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= +github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= github.com/hashicorp/terraform-plugin-sdk v1.6.0 h1:Um5hsAL7kKsfTHtan8lybY/d03F2bHu4fjRB1H6Ag4U= github.com/hashicorp/terraform-plugin-sdk v1.6.0/go.mod h1:H5QLx/uhwfxBZ59Bc5SqT19M4i+fYt7LZjHTpbLZiAg= -github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.1/go.mod h1:o3pdss6ynDZW9FfiZ+rETUH5LEVufrXdhwLU+5OiRo0= github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/vault v0.10.4 h1:4x0lHxui/ZRp/B3E0Auv1QNBJpzETqHR2kQD3mHSBJU= github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/heimweh/go-pagerduty v0.0.0-20210930203304-530eff2acdc6 h1:/D0VtHEOCdotE1vSB9XznceAjIGkUieZ4BF6VKUIqNU= +github.com/heimweh/go-pagerduty v0.0.0-20210930203304-530eff2acdc6/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/heroku/heroku-go/v5 v5.1.0 h1:3Qx1MxjzczSakhAZN4yRsvCI7kP0ldijK1XvfoYa4DE= github.com/heroku/heroku-go/v5 v5.1.0/go.mod h1:d+1QrZyjbnQJG1f8xIoVvMQRFLt3XRVZOdlm26Sr73U= +github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 h1:nqAlWFEdqI0ClbTDrhDvE/8LeQ4pftrqKUX9w5k0j3s= +github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/interagent/schematic v0.0.0-20180830170528-b5e8ba7aa570/go.mod h1:4X9u5iNUePRrRDdwjok6skjlQBXTcNfWa4C3uS1+5SQ= github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHck= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jefferai/jsonx v1.0.1 h1:GvWkLWihoLqDG0BSP45TUQJH9qsINX50PVrFULgpc/I= +github.com/jefferai/jsonx v1.0.1/go.mod h1:yFo3l2fcm7cZVHGq3HKLXE+Pd4RWuRjNBDHksM7XekQ= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.2.1 h1:S/EaQvW6FpWMYAvYvY+OBDvpaM+izu0oiwo5y0MH7U0= +github.com/jonboulle/clockwork v0.2.1/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboydell/logzio_client v1.2.0 h1:SkvYSgpJcLG0P9agjwF99oFiKtBiaXH8MZt7OmtwmvQ= github.com/jonboydell/logzio_client v1.2.0/go.mod h1:ZXJYF4M9/chuG+4fQDS9BN6CqXqokUjtQOjdMqzGC/Y= -github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7/go.mod h1:t4Tr0tn92eq5ISef4cS5plFAMYAqZlAXtgUcKE6y8nw= github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jstemmer/gotags v1.4.1/go.mod h1:b6J3X0bsLbR4C5SgSx3V3KjuWTtmRzcmWPbTkWZ49PA= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba h1:NARVGAAgEXvoMeNPHhPFt1SBt1VMznA3Gnz9d0qj+co= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.2.1/go.mod h1:RAoUvqkWr2rUa2I19qKMEVZQe4BVtcHGTMCUOcCU2Lg= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= +github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/iferr v0.0.0-20180615142939-bb332a3b1d91/go.mod h1:C2tFh8w3I6i4lnUJfoBx2Hwku3mgu4wPNTtUNp1i5KI= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labd/commercetools-go-sdk v0.0.0-20200309143931-ca72e918a79d h1:wI9Pc33M4Weg78J/fDFsKWTiEsAvriH6x4EHbcR3zus= -github.com/labd/commercetools-go-sdk v0.0.0-20200309143931-ca72e918a79d/go.mod h1:uOXGd793oxD6CZiPp30hzs4L511bcYSF0yPu17LBqAo= +github.com/labd/commercetools-go-sdk v0.3.1 h1:Fk8/VKKDSNHhyVhDywJdmzUt3JSpNoFZbHJndwjVBls= +github.com/labd/commercetools-go-sdk v0.3.1/go.mod h1:I+KKNALlg6PcSertsVA7E442koO99GT7gldWqwZlUGo= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/likexian/gokit v0.0.0-20190309162924-0a377eecf7aa/go.mod h1:QdfYv6y6qPA9pbBA2qXtoT8BMKha6UyNbxWGWl/9Jfk= github.com/likexian/gokit v0.0.0-20190418170008-ace88ad0983b/go.mod h1:KKqSnk/VVSW8kEyO2vVCXoanzEutKdlBAPohmGXkxCk= @@ -534,14 +913,22 @@ github.com/likexian/gokit v0.20.15/go.mod h1:kn+nTv3tqh6yhor9BC4Lfiu58SmH8NmQ2Pm github.com/likexian/simplejson-go v0.0.0-20190409170913-40473a74d76d/go.mod h1:Typ1BfnATYtZ/+/shXfFYLrovhFyuKvzwrdOnIDHlmg= github.com/likexian/simplejson-go v0.0.0-20190419151922-c1f9f0b4f084/go.mod h1:U4O1vIJvIKwbMZKUJ62lppfdvkCdVd2nfMimHK81eec= github.com/likexian/simplejson-go v0.0.0-20190502021454-d8787b4bfa0b/go.mod h1:3BWwtmKP9cXWwYCr5bkoVDEfLywacOv0s06OBEDpyt8= -github.com/linode/linodego v0.24.0 h1:o6hNS0T7jeikOfUHoJhUhA/e2QTCsw9MGccVmRHRLE4= -github.com/linode/linodego v0.24.0/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE= +github.com/linode/linodego v0.24.1 h1:3s7/F54z9XZfefzrFqnHMD9DIEYVyOddPm+gyTEFFzc= +github.com/linode/linodego v0.24.1/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= +github.com/mackerelio/mackerel-client-go v0.19.0 h1:DkYVD07fmklFTMKLaHcjtkU53Nt+nhvXNUSEeKfRSZs= +github.com/mackerelio/mackerel-client-go v0.19.0/go.mod h1:/GNOj+y1eFsd3CK8c6IQ/uS38/GT0+NWImk5YGJs5Lk= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b/go.mod h1:wr1VqkwW0AB5JS0QLy5GpVMS9E3VtRoSYXUYyVk46KY= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e h1:qqXczln0qwkVGcpQ+sQuPOVntt2FytYarXXxYSNJkgw= +github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= @@ -559,84 +946,130 @@ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mcuadros/go-lookup v0.0.0-20200831155250-80f87a4fa5ee h1:7Ac2RNGC8DAwDNd5uZyuYLoJOlVXyBGbO1VtFboDamk= -github.com/mcuadros/go-lookup v0.0.0-20200831155250-80f87a4fa5ee/go.mod h1:yd3I5pyIO5TrBH7+Ym94u8qp9xc6NTHAqESeI8kOJY8= +github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s= +github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY= github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= +github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= +github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA= github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mrparkers/terraform-provider-keycloak v0.0.0-20200506151941-509881368409 h1:TLDEP4t/KAbbIBVqMQlmf0MaLBm0eMAGHKtrOFNGHUM= github.com/mrparkers/terraform-provider-keycloak v0.0.0-20200506151941-509881368409/go.mod h1:q1krA85sGCNuxTOIcH9WSFf4nEO7he+IDDf5SW+xs1s= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/nicksnyder/go-i18n v1.10.1 h1:isfg77E/aCD7+0lD/D00ebR2MV5vgeQ276WYyDaCRQc= github.com/nicksnyder/go-i18n v1.10.1/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/ns1/ns1-go v2.4.0+incompatible h1:WYLNc1preJKfVVJL0zCOXfePlREOwrpJrDhJNn1nnLI= github.com/ns1/ns1-go v2.4.0+incompatible/go.mod h1:+5cGIDXMoO+J3+C8FJ8J0xkyiTdgCvDA+JXQ7f1cPKs= -github.com/nsf/gocode v0.0.0-20190302080247-5bee97b48836/go.mod h1:6Q8/OMaaKAgTX7/jt2bOXVDrm1eJhoNd+iwzghR7jvs= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/okta/okta-sdk-golang/v2 v2.6.3-0.20210923165359-20aeac44ab01 h1:eTw4NCD4FBAAT+tqx8qq2WhPjVwauVp//mvG4c3wrUY= +github.com/okta/okta-sdk-golang/v2 v2.6.3-0.20210923165359-20aeac44ab01/go.mod h1:0y8stgdplWMjaEbMr4mVtw0R+BdktpGZRw2sWKZWsMs= +github.com/okta/terraform-provider-okta v0.0.0-20210924173942-a5a664459d3b h1:ML6q0susBNxEEXZkifQGjY5ILGJHhU0a72Dm2DHEbSg= +github.com/okta/terraform-provider-okta v0.0.0-20210924173942-a5a664459d3b/go.mod h1:hVb3TxYi4ibGeUpue2Rqm84YhD/473w0Xv0uIlylUY8= github.com/olekukonko/tablewriter v0.0.3/go.mod h1:YZeBtGzYYEsCHp2LST/u/0NDwGkRoBtmn1cIWCJiS6M= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2Tm5gs= +github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.8 h1:qF/rRi8GSU2mjBXfJIyMj9GGmjedsV3Gm1uYbiGlCRk= +github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.8/go.mod h1:4OjcxgwdXzezqytxN534MooNmrxRD50geWZxTD7845s= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= +github.com/packethost/packngo v0.9.0 h1:dcrJFDNdbW+xCCNzWCmtol1x+hanEZmff5Myv/ku82U= +github.com/packethost/packngo v0.9.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 h1:pSCLCl6joCFRnjpeojzOpEYs4q7Vditq8fySFG5ap3Y= +github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/paultyng/go-newrelic/v4 v4.10.0 h1:6R2aC3vONWnfxbW00nAYZ9YSj7nJ3IvQRw2rG5KGijY= github.com/paultyng/go-newrelic/v4 v4.10.0/go.mod h1:RmSnSvZnV267IBAqv2/2RACv1YVmxaf+/ujOFS9DRb8= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -659,33 +1092,52 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/godef v1.1.2/go.mod h1:WtY9A/ovuQ+UakAJ1/CEqwwulX/WJjb2kgkokCHi/GY= +github.com/russellhaering/goxmldsig v1.1.0 h1:lK/zeJie2sqG52ZAlPNn1oBBqsIsEKypUUBGpYYF6lk= +github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/jsonrpc2 v0.0.0-20210201082850-366fbb520750 h1:j3HKQAXXj5vV3oHyg9pjK3uIM4bidukvv+tR2iJCvFA= +github.com/sourcegraph/jsonrpc2 v0.0.0-20210201082850-366fbb520750/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -695,23 +1147,30 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= +github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible h1:q+D/Y9jla3afgsIihtyhwyl0c2W+eRWNM9ohVwPiiPw= +github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c/go.mod h1:wk2XFUg6egk4tSDNZtXeKfe2G6690UVyt163PuUxBZk= +github.com/tencentyun/cos-go-sdk-v5 v0.7.19 h1:janAfTO4MglOrUFuKGTQJBuMc66+F7TgtEIt1wPsJ+k= +github.com/tencentyun/cos-go-sdk-v5 v0.7.19/go.mod h1:wQBO5HdAkLjj2q6XQiIfDSP8DXDNrppDRw2Kp/1BODA= github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew= -github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= -github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= @@ -719,19 +1178,35 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFy github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vultr/govultr v0.5.0 h1:iQzYhzbokmpDARbvIkvTkoyS7WMH82zVTKAL1PZ4JOA= github.com/vultr/govultr v0.5.0/go.mod h1:wZZXZbYbqyY1n3AldoeYNZK4Wnmmoq6dNFkvd5TV3ss= +github.com/xanzy/go-gitlab v0.50.2 h1:Qm/um2Jryuqusc6VmN7iZYVTQVzNynzSiuMJDnCU1wE= +github.com/xanzy/go-gitlab v0.50.2/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= @@ -740,6 +1215,8 @@ github.com/yandex-cloud/go-genproto v0.0.0-20200722140432-762fe965ce77 h1:ujojfQ github.com/yandex-cloud/go-genproto v0.0.0-20200722140432-762fe965ce77/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE= github.com/yandex-cloud/go-sdk v0.0.0-20200722140627-2194e5077f13 h1:llDpCOEwliajLr8eXtLPIVW0hzat4ETTakiCI+z/c6k= github.com/yandex-cloud/go-sdk v0.0.0-20200722140627-2194e5077f13/go.mod h1:LEdAMqa1v/7KYe4b13ALLkonuDxLph57ibUb50ctvJk= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -748,20 +1225,26 @@ github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLE github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.7.0 h1:yMqLinUwNCYkmiHjEH+luio1yGl35cjqVzjvdRg2WlY= -github.com/zclconf/go-cty v1.7.0/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= -github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= +github.com/zclconf/go-cty v1.8.4 h1:pwhhz5P+Fjxse7S7UriBrMu6AUJSZM5pKqGem1PjGAs= +github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= -github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a/go.mod h1:ofmGw6LrMypycsiWcyug6516EXpIxSbZ+uI9ppGypfY= +github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0= +github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= +github.com/zenazn/goji v0.9.1-0.20160507202103-64eb34159fe5/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zorkian/go-datadog-api v2.30.0+incompatible h1:R4ryGocppDqZZbnNc5EDR8xGWF/z/MxzWnqTUijDQes= github.com/zorkian/go-datadog-api v2.30.0+incompatible/go.mod h1:PkXwHX9CUQa/FpB9ZwAD45N1uhCW4MT/Wj7m36PbKss= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= +go.mongodb.org/mongo-driver v1.7.2 h1:pFttQyIiJUHEn50YfZgC9ECjITMT44oiN36uArf/OFg= +go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= @@ -771,26 +1254,34 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -817,25 +1308,28 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -843,15 +1337,14 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -864,63 +1357,86 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -930,44 +1446,53 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180824175216-6c1c5e93cdc1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -975,16 +1500,21 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190408220357-e5b8258f4918/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -999,31 +1529,37 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200226224502-204d844ad48d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200501155019-2658dc0cadb5 h1:skr8G4q25c51+6Dl9dOaUHiRYj1JB4V7DXGIDYsKe7Q= -golang.org/x/tools v0.0.0-20200501155019-2658dc0cadb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200612022331-742c5eb664c2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200624163319-25775e59acb7/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20200918232735-d647fc253266 h1:k7tVuG0g1JwmD3Jh8oAl1vQ1C3jb4Hi/dUl1wWDBJpQ= -golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201030143252-cf7a54d06671/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201105220310-78b158585360 h1:/9CzsU8hOpnSUCtem1vfWNgsVeCTgkMdx+VE5YIYxnU= golang.org/x/tools v0.0.0-20201105220310-78b158585360/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1044,27 +1580,25 @@ google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo= -google.golang.org/api v0.32.0 h1:Le77IccnTqEa8ryp9wIpX5W3zYm7Gf9LhOp9PHcwFts= -google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.35.0 h1:TBCmTTxUrRDA1iTctnK/fIeitxIZ+TQuaf0j29fmCGo= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0 h1:uWrpz12dpVPn7cojP82mk02XDgTJLDPc2KbVTxrWb4A= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1088,23 +1622,26 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200323114720-3f67cca34472/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYUO2VM9mDLqo2V6CFBY84lFSZAfoi4= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5 h1:B9nroC8SSX5GtbVvxPF9tYIVkaCpjhVLOrlAY8ONzm8= -google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba h1:HocWKLuilwaaLY56cHV38rw84wJ1nscA0Rs7OnO8mm8= google.golang.org/genproto v0.0.0-20201106154455-f9bfe239b0ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 h1:PYBmACG+YEv8uQPW0r1kJj8tR+gkF0UWq7iFdUezwEw= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1116,18 +1653,17 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1137,74 +1673,81 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/DataDog/dd-trace-go.v1 v1.24.1 h1:CGQIcKZxAsFtMTUiXw0TxBWwj+l+b2bS2V8l1bIsfk4= -gopkg.in/DataDog/dd-trace-go.v1 v1.24.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.19.0 h1:PTE3gBwP61sZfxOsROkUZbXONv+7N5Mw1Et6S+4NGBA= gopkg.in/go-playground/validator.v9 v9.19.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= +gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -k8s.io/api v0.17.5 h1:EkVieIbn1sC8YCDwckLKLpf+LoVofXYW72+LTZWo4aQ= -k8s.io/api v0.17.5/go.mod h1:0zV5/ungglgy2Rlm3QK8fbxkXVs+BSJWpJP/+8gUVLY= -k8s.io/apimachinery v0.17.5 h1:QAjfgeTtSGksdkgyaPrIb4lhU16FWMIzxKejYD5S0gc= -k8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0= -k8s.io/client-go v0.17.5 h1:Sm/9AQ415xPAX42JLKbJZnreXFgD2rVfDUDwOTm0gzA= -k8s.io/client-go v0.17.5/go.mod h1:S8uZpBpjJJdEH/fEyxcqg7Rn0P5jH+ilkgBHjriSmNo= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200316234421-82d701f24f9d/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191218082557-f07c713de883 h1:TA8t8OLS8m3/0dtTckekO0pCQ7qMnD19fsZTQEgCSKQ= -k8s.io/utils v0.0.0-20191218082557-f07c713de883/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= +k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= +k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= +k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= +k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= +k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/providers/alicloud/alicloud_provider.go b/providers/alicloud/alicloud_provider.go index 2dbd6b926..da20a2ebe 100644 --- a/providers/alicloud/alicloud_provider.go +++ b/providers/alicloud/alicloud_provider.go @@ -29,6 +29,8 @@ type AliCloudProvider struct { //nolint profile string } +const GlobalRegion = "alicloud-global" + // GetConfig Converts json config to go-cty func (p *AliCloudProvider) GetConfig() cty.Value { profile := p.profile @@ -72,37 +74,15 @@ func (p AliCloudProvider) GetResourceConnections() map[string]map[string][]strin // GetProviderData Used for generated HCL2 for the provider func (p AliCloudProvider) GetProviderData(arg ...string) map[string]interface{} { - args := p.Service.GetArgs() - profile := args["profile"].(string) - config, err := LoadConfigFromProfile(profile) - if err != nil { - fmt.Println("ERROR:", err) - } - - region := p.region - if region == "" { - region = config.RegionID - } - - if config.RAMRoleArn != "" { - return map[string]interface{}{ - "provider": map[string]interface{}{ - "alicloud": map[string]interface{}{ - "region": region, - "profile": profile, - "assume_role": map[string]interface{}{ - "role_arn": config.RAMRoleArn, - }, - }, - }, - } + alicloudConfig := map[string]interface{}{} + if p.region == GlobalRegion { + alicloudConfig["region"] = "cn-hangzhou" + } else { + alicloudConfig["region"] = p.region } return map[string]interface{}{ "provider": map[string]interface{}{ - "alicloud": map[string]interface{}{ - "region": region, - "profile": profile, - }, + "alicloud": alicloudConfig, }, } } diff --git a/providers/alicloud/dns.go b/providers/alicloud/dns.go index e434475b3..37f0f7355 100644 --- a/providers/alicloud/dns.go +++ b/providers/alicloud/dns.go @@ -26,7 +26,7 @@ type DNSGenerator struct { AliCloudService } -func resourceFromDomain(domain alidns.Domain) terraformutils.Resource { +func resourceFromDomain(domain alidns.DomainInDescribeDomains) terraformutils.Resource { return terraformutils.NewResource( domain.DomainName, // id domain.DomainId+"__"+domain.DomainName, // nolint @@ -50,12 +50,12 @@ func resourceFromDomainRecord(record alidns.Record) terraformutils.Resource { ) } -func initDomains(client *connectivity.AliyunClient) ([]alidns.Domain, error) { +func initDomains(client *connectivity.AliyunClient) ([]alidns.DomainInDescribeDomains, error) { remaining := 1 pageNumber := 1 pageSize := 10 - allDomains := make([]alidns.Domain, 0) + allDomains := make([]alidns.DomainInDescribeDomains, 0) for remaining > 0 { raw, err := client.WithDNSClient(func(alidnsClient *alidns.Client) (interface{}, error) { @@ -78,7 +78,7 @@ func initDomains(client *connectivity.AliyunClient) ([]alidns.Domain, error) { return allDomains, nil } -func initDomainRecords(client *connectivity.AliyunClient, allDomains []alidns.Domain) ([]alidns.Record, error) { +func initDomainRecords(client *connectivity.AliyunClient, allDomains []alidns.DomainInDescribeDomains) ([]alidns.Record, error) { allDomainRecords := make([]alidns.Record, 0) for _, domain := range allDomains { diff --git a/providers/alicloud/pvtz.go b/providers/alicloud/pvtz.go index adcc65322..6a57fcd56 100644 --- a/providers/alicloud/pvtz.go +++ b/providers/alicloud/pvtz.go @@ -54,8 +54,8 @@ func resourceFromZoneAttachmentResponse(zone pvtz.Zone) terraformutils.Resource func resourceFromZoneRecordResponse(record pvtz.Record, zoneID string) terraformutils.Resource { return terraformutils.NewResource( - strconv.Itoa(record.RecordId)+":"+zoneID, // id - strconv.Itoa(record.RecordId)+"__"+record.Rr, // name + strconv.FormatInt(record.RecordId, 10)+":"+zoneID, // id + strconv.FormatInt(record.RecordId, 10)+"__"+record.Rr, // name "alicloud_pvtz_zone_record", "alicloud", map[string]string{}, diff --git a/providers/alicloud/ram.go b/providers/alicloud/ram.go index be275c236..73768220f 100644 --- a/providers/alicloud/ram.go +++ b/providers/alicloud/ram.go @@ -27,7 +27,7 @@ type RAMGenerator struct { AliCloudService } -func resourceFromRAMRole(role ram.Role) terraformutils.Resource { +func resourceFromRAMRole(role ram.RoleInListRoles) terraformutils.Resource { return terraformutils.NewResource( role.RoleName, // id role.RoleId+"__"+role.RoleName, // name @@ -39,7 +39,7 @@ func resourceFromRAMRole(role ram.Role) terraformutils.Resource { ) } -func resourceFromRAMPolicy(policy ram.Policy, roleName string) terraformutils.Resource { +func resourceFromRAMPolicy(policy ram.PolicyInListPoliciesForRole, roleName string) terraformutils.Resource { // https://github.com/terraform-providers/terraform-provider-alicloud/blob/master/alicloud/resource_alicloud_ram_role_policy_attachment.go#L93 id := strings.Join([]string{"role", policy.PolicyName, policy.PolicyType, roleName}, ":") @@ -54,8 +54,8 @@ func resourceFromRAMPolicy(policy ram.Policy, roleName string) terraformutils.Re ) } -func initRoles(client *connectivity.AliyunClient) ([]ram.Role, error) { - allRoles := make([]ram.Role, 0) +func initRoles(client *connectivity.AliyunClient) ([]ram.RoleInListRoles, error) { + allRoles := make([]ram.RoleInListRoles, 0) raw, err := client.WithRAMClient(func(ramClient *ram.Client) (interface{}, error) { request := ram.CreateListRolesRequest() @@ -72,8 +72,8 @@ func initRoles(client *connectivity.AliyunClient) ([]ram.Role, error) { return allRoles, nil } -func initRAMPolicyAttachment(client *connectivity.AliyunClient, allRoles []ram.Role) ([]ram.Policy, []string, error) { - allRAMPolicies := make([]ram.Policy, 0) +func initRAMPolicyAttachment(client *connectivity.AliyunClient, allRoles []ram.RoleInListRoles) ([]ram.PolicyInListPoliciesForRole, []string, error) { + allRAMPolicies := make([]ram.PolicyInListPoliciesForRole, 0) roleNames := make([]string, 0) for _, role := range allRoles { diff --git a/providers/aws/accessanalyzer.go b/providers/aws/accessanalyzer.go index d464d3e80..1bc2840e7 100644 --- a/providers/aws/accessanalyzer.go +++ b/providers/aws/accessanalyzer.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/accessanalyzer" ) @@ -33,12 +32,16 @@ func (g *AccessAnalyzerGenerator) InitResources() error { if e != nil { return e } - svc := accessanalyzer.New(config) - p := accessanalyzer.NewListAnalyzersPaginator(svc.ListAnalyzersRequest(&accessanalyzer.ListAnalyzersInput{})) + svc := accessanalyzer.NewFromConfig(config) + p := accessanalyzer.NewListAnalyzersPaginator(svc, &accessanalyzer.ListAnalyzersInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, analyzer := range p.CurrentPage().Analyzers { - resourceName := aws.StringValue(analyzer.Name) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, analyzer := range page.Analyzers { + resourceName := *analyzer.Name resources = append(resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -48,5 +51,5 @@ func (g *AccessAnalyzerGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/acm.go b/providers/aws/acm.go index 161e90219..a0f6bc050 100644 --- a/providers/aws/acm.go +++ b/providers/aws/acm.go @@ -21,7 +21,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/acm" ) @@ -34,30 +33,30 @@ type ACMGenerator struct { } func (g *ACMGenerator) createCertificatesResources(svc *acm.Client) []terraformutils.Resource { - resources := []terraformutils.Resource{} - p := acm.NewListCertificatesPaginator(svc.ListCertificatesRequest(&acm.ListCertificatesInput{})) - for p.Next(context.Background()) { - for _, cert := range p.CurrentPage().CertificateSummaryList { - certArn := aws.StringValue(cert.CertificateArn) + var resources []terraformutils.Resource + p := acm.NewListCertificatesPaginator(svc, &acm.ListCertificatesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + log.Println(err) + return resources + } + for _, cert := range page.CertificateSummaryList { + certArn := *cert.CertificateArn certID := extractCertificateUUID(certArn) resources = append(resources, terraformutils.NewResource( certArn, - certID+"_"+strings.TrimSuffix(aws.StringValue(cert.DomainName), "."), + certID+"_"+strings.TrimSuffix(*cert.DomainName, "."), "aws_acm_certificate", "aws", map[string]string{ - "domain_name": aws.StringValue(cert.DomainName), + "domain_name": *cert.DomainName, }, acmAllowEmptyValues, acmAdditionalFields, )) } } - - if err := p.Err(); err != nil { - log.Println(err) - return resources - } return resources } @@ -68,7 +67,7 @@ func (g *ACMGenerator) InitResources() error { if e != nil { return e } - svc := acm.New(config) + svc := acm.NewFromConfig(config) g.Resources = g.createCertificatesResources(svc) return nil diff --git a/providers/aws/alb.go b/providers/aws/alb.go index 1770b3f38..89940f4b1 100644 --- a/providers/aws/alb.go +++ b/providers/aws/alb.go @@ -22,7 +22,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/hashicorp/terraform/helper/resource" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" ) var AlbAllowEmptyValues = []string{"tags.", "^condition."} @@ -32,12 +32,16 @@ type AlbGenerator struct { } func (g *AlbGenerator) loadLB(svc *elasticloadbalancingv2.Client) error { - p := elasticloadbalancingv2.NewDescribeLoadBalancersPaginator(svc.DescribeLoadBalancersRequest(&elasticloadbalancingv2.DescribeLoadBalancersInput{})) - for p.Next(context.Background()) { - for _, lb := range p.CurrentPage().LoadBalancers { - resourceName := aws.StringValue(lb.LoadBalancerName) + p := elasticloadbalancingv2.NewDescribeLoadBalancersPaginator(svc, &elasticloadbalancingv2.DescribeLoadBalancersInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, lb := range page.LoadBalancers { + resourceName := StringValue(lb.LoadBalancerName) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(lb.LoadBalancerArn), + *lb.LoadBalancerArn, resourceName, "aws_lb", "aws", @@ -49,14 +53,18 @@ func (g *AlbGenerator) loadLB(svc *elasticloadbalancingv2.Client) error { } } } - return p.Err() + return nil } func (g *AlbGenerator) loadLBListener(svc *elasticloadbalancingv2.Client, loadBalancerArn *string) error { - p := elasticloadbalancingv2.NewDescribeListenersPaginator(svc.DescribeListenersRequest(&elasticloadbalancingv2.DescribeListenersInput{LoadBalancerArn: loadBalancerArn})) - for p.Next(context.Background()) { - for _, ls := range p.CurrentPage().Listeners { - resourceName := aws.StringValue(ls.ListenerArn) + p := elasticloadbalancingv2.NewDescribeListenersPaginator(svc, &elasticloadbalancingv2.DescribeListenersInput{LoadBalancerArn: loadBalancerArn}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, ls := range page.Listeners { + resourceName := *ls.ListenerArn g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -74,23 +82,23 @@ func (g *AlbGenerator) loadLBListener(svc *elasticloadbalancingv2.Client, loadBa } } } - return p.Err() + return nil } func (g *AlbGenerator) loadLBListenerRule(svc *elasticloadbalancingv2.Client, listenerArn *string) error { var marker *string for { - lsrs, err := svc.DescribeRulesRequest(&elasticloadbalancingv2.DescribeRulesInput{ + lsrs, err := svc.DescribeRules(context.TODO(), &elasticloadbalancingv2.DescribeRulesInput{ ListenerArn: listenerArn, Marker: marker, - PageSize: aws.Int64(400)}, - ).Send(context.Background()) + PageSize: aws.Int32(400)}, + ) if err != nil { return err } for _, lsr := range lsrs.Rules { - if !aws.BoolValue(lsr.IsDefault) { - resourceName := aws.StringValue(lsr.RuleArn) + if !lsr.IsDefault { + resourceName := *lsr.RuleArn g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -108,15 +116,15 @@ func (g *AlbGenerator) loadLBListenerRule(svc *elasticloadbalancingv2.Client, li return nil } -func (g *AlbGenerator) loadLBListenerCertificate(svc *elasticloadbalancingv2.Client, loadBalancer *elasticloadbalancingv2.Listener) error { - lcs, err := svc.DescribeListenerCertificatesRequest(&elasticloadbalancingv2.DescribeListenerCertificatesInput{ +func (g *AlbGenerator) loadLBListenerCertificate(svc *elasticloadbalancingv2.Client, loadBalancer *types.Listener) error { + lcs, err := svc.DescribeListenerCertificates(context.TODO(), &elasticloadbalancingv2.DescribeListenerCertificatesInput{ ListenerArn: loadBalancer.ListenerArn, - }).Send(context.Background()) + }) if err != nil { return err } for _, lc := range lcs.Certificates { - certificateArn := aws.StringValue(lc.CertificateArn) + certificateArn := *lc.CertificateArn if certificateArn == *loadBalancer.Certificates[0].CertificateArn { // discard default certificate continue } @@ -137,12 +145,16 @@ func (g *AlbGenerator) loadLBListenerCertificate(svc *elasticloadbalancingv2.Cli } func (g *AlbGenerator) loadLBTargetGroup(svc *elasticloadbalancingv2.Client) error { - p := elasticloadbalancingv2.NewDescribeTargetGroupsPaginator(svc.DescribeTargetGroupsRequest(&elasticloadbalancingv2.DescribeTargetGroupsInput{})) - for p.Next(context.Background()) { - for _, tg := range p.CurrentPage().TargetGroups { - resourceName := aws.StringValue(tg.TargetGroupName) + p := elasticloadbalancingv2.NewDescribeTargetGroupsPaginator(svc, &elasticloadbalancingv2.DescribeTargetGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, tg := range page.TargetGroups { + resourceName := StringValue(tg.TargetGroupName) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(tg.TargetGroupArn), + *tg.TargetGroupArn, resourceName, "aws_lb_target_group", "aws", @@ -154,26 +166,26 @@ func (g *AlbGenerator) loadLBTargetGroup(svc *elasticloadbalancingv2.Client) err } } } - return p.Err() + return nil } func (g *AlbGenerator) loadTargetGroupTargets(svc *elasticloadbalancingv2.Client, targetGroupArn *string) error { - targetHealths, err := svc.DescribeTargetHealthRequest(&elasticloadbalancingv2.DescribeTargetHealthInput{ + targetHealths, err := svc.DescribeTargetHealth(context.TODO(), &elasticloadbalancingv2.DescribeTargetHealthInput{ TargetGroupArn: targetGroupArn, - }).Send(context.Background()) + }) if err != nil { return err } for _, tgh := range targetHealths.TargetHealthDescriptions { - id := resource.PrefixedUniqueId(fmt.Sprintf("%s-", aws.StringValue(targetGroupArn))) + id := fmt.Sprintf("%s-%s", *targetGroupArn, *tgh.Target.Id) g.Resources = append(g.Resources, terraformutils.NewResource( id, id, "aws_lb_target_group_attachment", "aws", map[string]string{ - "target_id": aws.StringValue(tgh.Target.Id), - "target_group_arn": aws.StringValue(targetGroupArn), + "target_id": *tgh.Target.Id, + "target_group_arn": *targetGroupArn, }, AlbAllowEmptyValues, map[string]interface{}{}, @@ -188,7 +200,7 @@ func (g *AlbGenerator) InitResources() error { if e != nil { return e } - svc := elasticloadbalancingv2.New(config) + svc := elasticloadbalancingv2.NewFromConfig(config) if err := g.loadLB(svc); err != nil { return err } diff --git a/providers/aws/api_gateway.go b/providers/aws/api_gateway.go index c0d5c652c..70b435d62 100644 --- a/providers/aws/api_gateway.go +++ b/providers/aws/api_gateway.go @@ -22,7 +22,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/GoogleCloudPlatform/terraformer/terraformutils/terraformerstring" "github.com/aws/aws-sdk-go-v2/service/apigateway" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/service/apigateway/types" ) var apiGatewayAllowEmptyValues = []string{"tags.", "parent_id", "path_part"} @@ -36,7 +36,7 @@ func (g *APIGatewayGenerator) InitResources() error { if e != nil { return e } - svc := apigateway.New(config) + svc := apigateway.NewFromConfig(config) if err := g.loadRestApis(svc); err != nil { return err @@ -52,9 +52,13 @@ func (g *APIGatewayGenerator) InitResources() error { } func (g *APIGatewayGenerator) loadRestApis(svc *apigateway.Client) error { - p := apigateway.NewGetRestApisPaginator(svc.GetRestApisRequest(&apigateway.GetRestApisInput{})) - for p.Next(context.Background()) { - for _, restAPI := range p.CurrentPage().Items { + p := apigateway.NewGetRestApisPaginator(svc, &apigateway.GetRestApisInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, restAPI := range page.Items { if g.shouldFilterRestAPI(restAPI.Tags) { continue } @@ -84,7 +88,7 @@ func (g *APIGatewayGenerator) loadRestApis(svc *apigateway.Client) error { } } } - return p.Err() + return nil } func (g *APIGatewayGenerator) shouldFilterRestAPI(tags map[string]string) bool { @@ -101,14 +105,14 @@ func (g *APIGatewayGenerator) shouldFilterRestAPI(tags map[string]string) bool { } func (g *APIGatewayGenerator) loadStages(svc *apigateway.Client, restAPIID *string) error { - output, err := svc.GetStagesRequest(&apigateway.GetStagesInput{ + output, err := svc.GetStages(context.TODO(), &apigateway.GetStagesInput{ RestApiId: restAPIID, - }).Send(context.Background()) + }) if err != nil { return err } - for _, stage := range output.GetStagesOutput.Item { - stageID := *restAPIID + "/" + *stage.StageName + for _, stage := range output.Item { + stageID := *restAPIID + "/" + StringValue(stage.StageName) g.Resources = append(g.Resources, terraformutils.NewResource( stageID, stageID, @@ -126,11 +130,15 @@ func (g *APIGatewayGenerator) loadStages(svc *apigateway.Client, restAPIID *stri } func (g *APIGatewayGenerator) loadResources(svc *apigateway.Client, restAPIID *string) error { - p := apigateway.NewGetResourcesPaginator(svc.GetResourcesRequest(&apigateway.GetResourcesInput{ + p := apigateway.NewGetResourcesPaginator(svc, &apigateway.GetResourcesInput{ RestApiId: restAPIID, - })) - for p.Next(context.Background()) { - for _, resource := range p.CurrentPage().Items { + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, resource := range page.Items { resourceID := *resource.Id g.Resources = append(g.Resources, terraformutils.NewResource( resourceID, @@ -138,10 +146,10 @@ func (g *APIGatewayGenerator) loadResources(svc *apigateway.Client, restAPIID *s "aws_api_gateway_resource", "aws", map[string]string{ - "path": aws.StringValue(resource.Path), - "path_part": aws.StringValue(resource.PathPart), - "partent_id": aws.StringValue(resource.ParentId), - "rest_api_id": aws.StringValue(restAPIID), + "path": StringValue(resource.Path), + "path_part": StringValue(resource.PathPart), + "partent_id": StringValue(resource.ParentId), + "rest_api_id": StringValue(restAPIID), }, apiGatewayAllowEmptyValues, map[string]interface{}{}, @@ -152,15 +160,19 @@ func (g *APIGatewayGenerator) loadResources(svc *apigateway.Client, restAPIID *s } } } - return p.Err() + return nil } func (g *APIGatewayGenerator) loadModels(svc *apigateway.Client, restAPIID *string) error { - p := apigateway.NewGetModelsPaginator(svc.GetModelsRequest(&apigateway.GetModelsInput{ + p := apigateway.NewGetModelsPaginator(svc, &apigateway.GetModelsInput{ RestApiId: restAPIID, - })) - for p.Next(context.Background()) { - for _, model := range p.CurrentPage().Items { + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return nil + } + for _, model := range page.Items { resourceID := *model.Id g.Resources = append(g.Resources, terraformutils.NewResource( resourceID, @@ -168,20 +180,20 @@ func (g *APIGatewayGenerator) loadModels(svc *apigateway.Client, restAPIID *stri "aws_api_gateway_model", "aws", map[string]string{ - "name": aws.StringValue(model.Name), - "content_type": aws.StringValue(model.ContentType), - "schema": aws.StringValue(model.Schema), - "rest_api_id": aws.StringValue(restAPIID), + "name": StringValue(model.Name), + "content_type": StringValue(model.ContentType), + "schema": StringValue(model.Schema), + "rest_api_id": StringValue(restAPIID), }, apiGatewayAllowEmptyValues, map[string]interface{}{}, )) } } - return p.Err() + return nil } -func (g *APIGatewayGenerator) loadResourceMethods(svc *apigateway.Client, restAPIID *string, resource apigateway.Resource) error { +func (g *APIGatewayGenerator) loadResourceMethods(svc *apigateway.Client, restAPIID *string, resource types.Resource) error { for httpMethod, method := range resource.ResourceMethods { methodID := *restAPIID + "/" + *resource.Id + "/" + httpMethod authorizationType := "NONE" @@ -204,17 +216,17 @@ func (g *APIGatewayGenerator) loadResourceMethods(svc *apigateway.Client, restAP map[string]interface{}{}, )) - methodDetails, err := svc.GetMethodRequest(&apigateway.GetMethodInput{ + methodDetails, err := svc.GetMethod(context.TODO(), &apigateway.GetMethodInput{ HttpMethod: &httpMethod, ResourceId: resource.Id, RestApiId: restAPIID, - }).Send(context.Background()) + }) if err != nil { return err } if methodDetails.MethodIntegration != nil { - typeString, _ := methodDetails.MethodIntegration.Type.MarshalValue() + typeString := string(methodDetails.MethodIntegration.Type) g.Resources = append(g.Resources, terraformutils.NewResource( methodID, methodID, @@ -229,11 +241,11 @@ func (g *APIGatewayGenerator) loadResourceMethods(svc *apigateway.Client, restAP apiGatewayAllowEmptyValues, map[string]interface{}{}, )) - integrationDetails, err := svc.GetIntegrationRequest(&apigateway.GetIntegrationInput{ + integrationDetails, err := svc.GetIntegration(context.TODO(), &apigateway.GetIntegrationInput{ HttpMethod: &httpMethod, ResourceId: resource.Id, RestApiId: restAPIID, - }).Send(context.Background()) + }) if err != nil { return err } @@ -281,18 +293,18 @@ func (g *APIGatewayGenerator) loadResourceMethods(svc *apigateway.Client, restAP func (g *APIGatewayGenerator) loadResponses(svc *apigateway.Client, restAPIID *string) error { var position *string for { - response, err := svc.GetGatewayResponsesRequest(&apigateway.GetGatewayResponsesInput{ + response, err := svc.GetGatewayResponses(context.TODO(), &apigateway.GetGatewayResponsesInput{ RestApiId: restAPIID, Position: position, - }).Send(context.Background()) + }) if err != nil { return err } for _, response := range response.Items { - if aws.BoolValue(response.DefaultResponse) { + if response.DefaultResponse { continue } - responseTypeString, _ := response.ResponseType.MarshalValue() + responseTypeString := string(response.ResponseType) responseID := *restAPIID + "/" + responseTypeString g.Resources = append(g.Resources, terraformutils.NewResource( responseID, @@ -318,10 +330,10 @@ func (g *APIGatewayGenerator) loadResponses(svc *apigateway.Client, restAPIID *s func (g *APIGatewayGenerator) loadDocumentationParts(svc *apigateway.Client, restAPIID *string) error { var position *string for { - response, err := svc.GetDocumentationPartsRequest(&apigateway.GetDocumentationPartsInput{ + response, err := svc.GetDocumentationParts(context.TODO(), &apigateway.GetDocumentationPartsInput{ RestApiId: restAPIID, Position: position, - }).Send(context.Background()) + }) if err != nil { return err } @@ -346,10 +358,10 @@ func (g *APIGatewayGenerator) loadDocumentationParts(svc *apigateway.Client, res func (g *APIGatewayGenerator) loadAuthorizers(svc *apigateway.Client, restAPIID *string) error { var position *string for { - response, err := svc.GetAuthorizersRequest(&apigateway.GetAuthorizersInput{ + response, err := svc.GetAuthorizers(context.TODO(), &apigateway.GetAuthorizersInput{ RestApiId: restAPIID, Position: position, - }).Send(context.Background()) + }) if err != nil { return err } @@ -361,7 +373,7 @@ func (g *APIGatewayGenerator) loadAuthorizers(svc *apigateway.Client, restAPIID "aws", map[string]string{ "rest_api_id": *restAPIID, - "name": aws.StringValue(authorizer.Name), + "name": StringValue(authorizer.Name), }, apiGatewayAllowEmptyValues, map[string]interface{}{}, @@ -376,9 +388,13 @@ func (g *APIGatewayGenerator) loadAuthorizers(svc *apigateway.Client, restAPIID } func (g *APIGatewayGenerator) loadVpcLinks(svc *apigateway.Client) error { - p := apigateway.NewGetVpcLinksPaginator(svc.GetVpcLinksRequest(&apigateway.GetVpcLinksInput{})) - for p.Next(context.Background()) { - for _, vpcLink := range p.CurrentPage().Items { + p := apigateway.NewGetVpcLinksPaginator(svc, &apigateway.GetVpcLinksInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, vpcLink := range page.Items { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *vpcLink.Id, *vpcLink.Name, @@ -387,13 +403,17 @@ func (g *APIGatewayGenerator) loadVpcLinks(svc *apigateway.Client) error { apiGatewayAllowEmptyValues)) } } - return p.Err() + return nil } func (g *APIGatewayGenerator) loadUsagePlans(svc *apigateway.Client) error { - p := apigateway.NewGetUsagePlansPaginator(svc.GetUsagePlansRequest(&apigateway.GetUsagePlansInput{})) - for p.Next(context.Background()) { - for _, usagePlan := range p.CurrentPage().Items { + p := apigateway.NewGetUsagePlansPaginator(svc, &apigateway.GetUsagePlansInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, usagePlan := range page.Items { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *usagePlan.Id, *usagePlan.Name, @@ -402,5 +422,5 @@ func (g *APIGatewayGenerator) loadUsagePlans(svc *apigateway.Client) error { apiGatewayAllowEmptyValues)) } } - return p.Err() + return nil } diff --git a/providers/aws/appsync.go b/providers/aws/appsync.go index 92700ccd8..af8180e6f 100644 --- a/providers/aws/appsync.go +++ b/providers/aws/appsync.go @@ -17,13 +17,13 @@ func (g *AppSyncGenerator) InitResources() error { return e } - svc := appsync.New(config) + svc := appsync.NewFromConfig(config) var nextToken *string for { - apis, err := svc.ListGraphqlApisRequest(&appsync.ListGraphqlApisInput{ + apis, err := svc.ListGraphqlApis(context.TODO(), &appsync.ListGraphqlApisInput{ NextToken: nextToken, - }).Send(context.Background()) + }) if err != nil { return err } diff --git a/providers/aws/autoscaling.go b/providers/aws/autoscaling.go index fb696d5ce..b6038d073 100644 --- a/providers/aws/autoscaling.go +++ b/providers/aws/autoscaling.go @@ -32,10 +32,14 @@ type AutoScalingGenerator struct { } func (g *AutoScalingGenerator) loadAutoScalingGroups(svc *autoscaling.Client) error { - p := autoscaling.NewDescribeAutoScalingGroupsPaginator(svc.DescribeAutoScalingGroupsRequest(&autoscaling.DescribeAutoScalingGroupsInput{})) - for p.Next(context.Background()) { - for _, asg := range p.CurrentPage().AutoScalingGroups { - resourceName := aws.StringValue(asg.AutoScalingGroupName) + p := autoscaling.NewDescribeAutoScalingGroupsPaginator(svc, &autoscaling.DescribeAutoScalingGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, asg := range page.AutoScalingGroups { + resourceName := StringValue(asg.AutoScalingGroupName) g.Resources = append(g.Resources, terraformutils.NewResource( resourceName, resourceName, @@ -51,17 +55,21 @@ func (g *AutoScalingGenerator) loadAutoScalingGroups(svc *autoscaling.Client) er )) } } - return p.Err() + return nil } func (g *AutoScalingGenerator) loadLaunchConfigurations(svc *autoscaling.Client) error { - p := autoscaling.NewDescribeLaunchConfigurationsPaginator(svc.DescribeLaunchConfigurationsRequest(&autoscaling.DescribeLaunchConfigurationsInput{})) - for p.Next(context.Background()) { - for _, lc := range p.CurrentPage().LaunchConfigurations { - resourceName := aws.StringValue(lc.LaunchConfigurationName) + p := autoscaling.NewDescribeLaunchConfigurationsPaginator(svc, &autoscaling.DescribeLaunchConfigurationsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, lc := range page.LaunchConfigurations { + resourceName := StringValue(lc.LaunchConfigurationName) attributes := map[string]string{} // only for LaunchConfigurations with userdata, we want get user_data_base64 - if aws.StringValue(lc.UserData) != "" { + if StringValue(lc.UserData) != "" { attributes["user_data_base64"] = "=" // need set not empty string to get user_data_base64 from provider } g.Resources = append(g.Resources, terraformutils.NewResource( @@ -75,25 +83,29 @@ func (g *AutoScalingGenerator) loadLaunchConfigurations(svc *autoscaling.Client) )) } } - return p.Err() + return nil } func (g *AutoScalingGenerator) loadLaunchTemplates(config aws.Config) error { - ec2svc := ec2.New(config) + ec2svc := ec2.NewFromConfig(config) - p := ec2.NewDescribeLaunchTemplatesPaginator(ec2svc.DescribeLaunchTemplatesRequest(&ec2.DescribeLaunchTemplatesInput{})) - for p.Next(context.Background()) { - for _, lt := range p.CurrentPage().LaunchTemplates { + p := ec2.NewDescribeLaunchTemplatesPaginator(ec2svc, &ec2.DescribeLaunchTemplatesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, lt := range page.LaunchTemplates { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(lt.LaunchTemplateId), - aws.StringValue(lt.LaunchTemplateName), + StringValue(lt.LaunchTemplateId), + StringValue(lt.LaunchTemplateName), "aws_launch_template", "aws", AsgAllowEmptyValues, )) } } - return p.Err() + return nil } // Generate TerraformResources from AWS API, @@ -105,7 +117,7 @@ func (g *AutoScalingGenerator) InitResources() error { if e != nil { return e } - svc := autoscaling.New(config) + svc := autoscaling.NewFromConfig(config) if err := g.loadAutoScalingGroups(svc); err != nil { return err } diff --git a/providers/aws/aws_provider.go b/providers/aws/aws_provider.go index ae038747a..8279ac4b0 100644 --- a/providers/aws/aws_provider.go +++ b/providers/aws/aws_provider.go @@ -30,6 +30,7 @@ type AWSProvider struct { //nolint } const GlobalRegion = "aws-global" +const MainRegionPublicPartition = "us-east-1" const NoRegion = "" // SupportedGlobalResources should be bound to a default region. AWS doesn't specify in which region default services are @@ -39,6 +40,7 @@ const NoRegion = "" var SupportedGlobalResources = []string{ "budgets", "cloudfront", + "ecrpublic", "iam", "organization", "route53", @@ -142,7 +144,7 @@ func (p AWSProvider) GetProviderData(arg ...string) map[string]interface{} { awsConfig := map[string]interface{}{} if p.region == GlobalRegion { - awsConfig["region"] = "us-east-1" // For TF to workaround terraform-providers/terraform-provider-aws#1043 + awsConfig["region"] = MainRegionPublicPartition // For TF to workaround terraform-providers/terraform-provider-aws#1043 } else if p.region != NoRegion { awsConfig["region"] = p.region } @@ -233,10 +235,12 @@ func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGen "api_gateway": &AwsFacade{service: &APIGatewayGenerator{}}, "appsync": &AwsFacade{service: &AppSyncGenerator{}}, "auto_scaling": &AwsFacade{service: &AutoScalingGenerator{}}, + "batch": &AwsFacade{service: &BatchGenerator{}}, "budgets": &AwsFacade{service: &BudgetsGenerator{}}, "cloud9": &AwsFacade{service: &Cloud9Generator{}}, "cloudformation": &AwsFacade{service: &CloudFormationGenerator{}}, "cloudfront": &AwsFacade{service: &CloudFrontGenerator{}}, + "cloudhsm": &AwsFacade{service: &CloudHsmGenerator{}}, "cloudtrail": &AwsFacade{service: &CloudTrailGenerator{}}, "cloudwatch": &AwsFacade{service: &CloudWatchGenerator{}}, "codebuild": &AwsFacade{service: &CodeBuildGenerator{}}, @@ -248,10 +252,12 @@ func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGen "customer_gateway": &AwsFacade{service: &CustomerGatewayGenerator{}}, "datapipeline": &AwsFacade{service: &DataPipelineGenerator{}}, "devicefarm": &AwsFacade{service: &DeviceFarmGenerator{}}, + "docdb": &AwsFacade{service: &DocDBGenerator{}}, "dynamodb": &AwsFacade{service: &DynamoDbGenerator{}}, "ebs": &AwsFacade{service: &EbsGenerator{}}, "ec2_instance": &AwsFacade{service: &Ec2Generator{}}, "ecr": &AwsFacade{service: &EcrGenerator{}}, + "ecrpublic": &AwsFacade{service: &EcrPublicGenerator{}}, "ecs": &AwsFacade{service: &EcsGenerator{}}, "efs": &AwsFacade{service: &EfsGenerator{}}, "eks": &AwsFacade{service: &EksGenerator{}}, @@ -276,6 +282,7 @@ func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGen "msk": &AwsFacade{service: &MskGenerator{}}, "nacl": &AwsFacade{service: &NaclGenerator{}}, "nat": &AwsFacade{service: &NatGatewayGenerator{}}, + "opsworks": &AwsFacade{service: &OpsworksGenerator{}}, "organization": &AwsFacade{service: &OrganizationGenerator{}}, "qldb": &AwsFacade{service: &QLDBGenerator{}}, "rds": &AwsFacade{service: &RDSGenerator{}}, @@ -291,6 +298,7 @@ func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGen "sg": &AwsFacade{service: &SecurityGenerator{}}, "sqs": &AwsFacade{service: &SqsGenerator{}}, "sns": &AwsFacade{service: &SnsGenerator{}}, + "ssm": &AwsFacade{service: &SsmGenerator{}}, "subnet": &AwsFacade{service: &SubnetGenerator{}}, "swf": &AwsFacade{service: &SWFGenerator{}}, "transit_gateway": &AwsFacade{service: &TransitGatewayGenerator{}}, @@ -304,3 +312,10 @@ func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGen "xray": &AwsFacade{service: &XrayGenerator{}}, } } + +func StringValue(value *string) string { + if value != nil { + return *value + } + return "" +} diff --git a/providers/aws/aws_service.go b/providers/aws/aws_service.go index 1dc2e9e6b..03fd64de4 100644 --- a/providers/aws/aws_service.go +++ b/providers/aws/aws_service.go @@ -22,8 +22,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/external" - "github.com/aws/aws-sdk-go-v2/aws/stscreds" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" "github.com/GoogleCloudPlatform/terraformer/terraformutils" ) @@ -34,20 +34,26 @@ type AWSService struct { //nolint var awsVariable = regexp.MustCompile(`(\${[0-9A-Za-z:]+})`) +var configCache *aws.Config + func (s *AWSService) generateConfig() (aws.Config, error) { - config, e := s.buildBaseConfig() + if configCache != nil { + return *configCache, nil + } + + baseConfig, e := s.buildBaseConfig() if e != nil { - return config, e + return baseConfig, e } if s.Verbose { - config.LogLevel = aws.LogDebugWithHTTPBody + baseConfig.ClientLogMode = aws.LogRequestWithBody & aws.LogResponseWithBody } - creds, e := config.Credentials.Retrieve(context.Background()) + creds, e := baseConfig.Credentials.Retrieve(context.TODO()) if e != nil { - return config, e + return baseConfig, e } // terraform cannot ask for MFA token, so we need to pass STS session token, which might contain credentials with MFA requirement @@ -60,17 +66,22 @@ func (s *AWSService) generateConfig() (aws.Config, error) { os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken) } } - - return config, nil + configCache = &baseConfig + return baseConfig, nil } func (s *AWSService) buildBaseConfig() (aws.Config, error) { + var loadOptions []func(*config.LoadOptions) error + if s.GetArgs()["profile"].(string) != "" { + loadOptions = append(loadOptions, config.WithSharedConfigProfile(s.GetArgs()["profile"].(string))) + } if s.GetArgs()["region"].(string) != "" { - return external.LoadDefaultAWSConfig( - external.WithRegion(s.GetArgs()["region"].(string)), - external.WithMFATokenFunc(stscreds.StdinTokenProvider)) + os.Setenv("AWS_REGION", s.GetArgs()["region"].(string)) } - return external.LoadDefaultAWSConfig(external.WithMFATokenFunc(stscreds.StdinTokenProvider)) + loadOptions = append(loadOptions, config.WithAssumeRoleCredentialOptions(func(options *stscreds.AssumeRoleOptions) { + options.TokenProvider = stscreds.StdinTokenProvider + })) + return config.LoadDefaultConfig(context.TODO(), loadOptions...) } // for CF interpolation and IAM Policy variables @@ -79,8 +90,8 @@ func (*AWSService) escapeAwsInterpolation(str string) string { } func (s *AWSService) getAccountNumber(config aws.Config) (*string, error) { - stsSvc := sts.New(config) - identity, err := stsSvc.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{}).Send(context.Background()) + stsSvc := sts.NewFromConfig(config) + identity, err := stsSvc.GetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{}) if err != nil { return nil, err } diff --git a/providers/aws/batch.go b/providers/aws/batch.go new file mode 100644 index 000000000..544b86cc1 --- /dev/null +++ b/providers/aws/batch.go @@ -0,0 +1,113 @@ +package aws + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/batch" +) + +var BatchAllowEmptyValues = []string{"tags."} + +var BatchAdditionalFields = map[string]interface{}{} + +type BatchGenerator struct { + AWSService +} + +func (g *BatchGenerator) InitResources() error { + config, e := g.generateConfig() + if e != nil { + return e + } + batchClient := batch.NewFromConfig(config) + + if err := g.loadComputeEnvironments(batchClient); err != nil { + return err + } + if err := g.loadJobDefinitions(batchClient); err != nil { + return err + } + if err := g.loadJobQueues(batchClient); err != nil { + return err + } + + return nil +} + +func (g *BatchGenerator) loadComputeEnvironments(batchClient *batch.Client) error { + p := batch.NewDescribeComputeEnvironmentsPaginator(batchClient, &batch.DescribeComputeEnvironmentsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, computeEnvironment := range page.ComputeEnvironments { + computeEnvironmentName := StringValue(computeEnvironment.ComputeEnvironmentName) + g.Resources = append(g.Resources, terraformutils.NewResource( + computeEnvironmentName, + computeEnvironmentName, + "aws_batch_compute_environment", + "aws", + map[string]string{ + "compute_environment_name": computeEnvironmentName, + }, + BatchAllowEmptyValues, + BatchAdditionalFields, + )) + } + } + return nil +} + +func (g *BatchGenerator) loadJobDefinitions(batchClient *batch.Client) error { + p := batch.NewDescribeJobDefinitionsPaginator(batchClient, &batch.DescribeJobDefinitionsInput{ + Status: aws.String("ACTIVE"), + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, jobDefinition := range page.JobDefinitions { + jobDefinitionName := StringValue(jobDefinition.JobDefinitionName) + g.Resources = append(g.Resources, terraformutils.NewResource( + jobDefinitionName, + jobDefinitionName, + "aws_batch_job_definition", + "aws", + map[string]string{ + "arn": StringValue(jobDefinition.JobDefinitionArn), + }, + BatchAllowEmptyValues, + BatchAdditionalFields, + )) + } + } + return nil +} + +func (g *BatchGenerator) loadJobQueues(batchClient *batch.Client) error { + p := batch.NewDescribeJobQueuesPaginator(batchClient, &batch.DescribeJobQueuesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, jobQueue := range page.JobQueues { + jobQueueName := StringValue(jobQueue.JobQueueName) + g.Resources = append(g.Resources, terraformutils.NewResource( + jobQueueName, + jobQueueName, + "aws_batch_job_queue", + "aws", + map[string]string{}, + BatchAllowEmptyValues, + BatchAdditionalFields, + )) + } + } + return nil +} diff --git a/providers/aws/budgets.go b/providers/aws/budgets.go index d6e72d3df..b8e62ac7e 100644 --- a/providers/aws/budgets.go +++ b/providers/aws/budgets.go @@ -19,18 +19,18 @@ import ( "fmt" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/budgets" + "github.com/aws/aws-sdk-go-v2/service/budgets/types" ) type BudgetsGenerator struct { AWSService } -func (g *BudgetsGenerator) createResources(budgets []budgets.Budget, account *string) []terraformutils.Resource { +func (g *BudgetsGenerator) createResources(budgets []types.Budget, account *string) []terraformutils.Resource { var resources []terraformutils.Resource for _, budget := range budgets { - resourceName := aws.StringValue(budget.BudgetName) + resourceName := StringValue(budget.BudgetName) resources = append(resources, terraformutils.NewSimpleResource( fmt.Sprintf("%s:%s", *account, resourceName), resourceName, @@ -46,14 +46,14 @@ func (g *BudgetsGenerator) InitResources() error { if e != nil { return e } - budgetsSvc := budgets.New(config) + budgetsSvc := budgets.NewFromConfig(config) account, err := g.getAccountNumber(config) if err != nil { return err } - output, err := budgetsSvc.DescribeBudgetsRequest(&budgets.DescribeBudgetsInput{AccountId: account}).Send(context.Background()) + output, err := budgetsSvc.DescribeBudgets(context.TODO(), &budgets.DescribeBudgetsInput{AccountId: account}) if err != nil { return err } diff --git a/providers/aws/cloud9.go b/providers/aws/cloud9.go index ad55f04ca..7aadd23cb 100644 --- a/providers/aws/cloud9.go +++ b/providers/aws/cloud9.go @@ -19,6 +19,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/cloud9" + "github.com/aws/aws-sdk-go-v2/service/cloud9/types" ) var cloud9AllowEmptyValues = []string{"tags."} @@ -32,17 +33,17 @@ func (g *Cloud9Generator) InitResources() error { if e != nil { return e } - svc := cloud9.New(config) - output, err := svc.ListEnvironmentsRequest(&cloud9.ListEnvironmentsInput{}).Send(context.Background()) + svc := cloud9.NewFromConfig(config) + output, err := svc.ListEnvironments(context.TODO(), &cloud9.ListEnvironmentsInput{}) if err != nil { return err } for _, environmentID := range output.EnvironmentIds { - details, _ := svc.DescribeEnvironmentStatusRequest(&cloud9.DescribeEnvironmentStatusInput{ + details, _ := svc.DescribeEnvironmentStatus(context.TODO(), &cloud9.DescribeEnvironmentStatusInput{ EnvironmentId: &environmentID, - }).Send(context.Background()) - if details.Status == cloud9.EnvironmentStatusError || - details.Status == cloud9.EnvironmentStatusDeleting { + }) + if details.Status == types.EnvironmentStatusError || + details.Status == types.EnvironmentStatusDeleting { continue } g.Resources = append(g.Resources, terraformutils.NewSimpleResource( diff --git a/providers/aws/cloud_front.go b/providers/aws/cloud_front.go index 481d05bea..b7f63bec4 100644 --- a/providers/aws/cloud_front.go +++ b/providers/aws/cloud_front.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/cloudfront" ) @@ -33,13 +32,17 @@ func (g *CloudFrontGenerator) InitResources() error { if e != nil { return e } - svc := cloudfront.New(config) - p := cloudfront.NewListDistributionsPaginator(svc.ListDistributionsRequest(&cloudfront.ListDistributionsInput{})) - for p.Next(context.Background()) { - for _, distribution := range p.CurrentPage().DistributionList.Items { + svc := cloudfront.NewFromConfig(config) + p := cloudfront.NewListDistributionsPaginator(svc, &cloudfront.ListDistributionsInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, distribution := range page.DistributionList.Items { r := terraformutils.NewResource( - aws.StringValue(distribution.Id), - aws.StringValue(distribution.Id), + StringValue(distribution.Id), + StringValue(distribution.Id), "aws_cloudfront_distribution", "aws", map[string]string{ @@ -52,5 +55,5 @@ func (g *CloudFrontGenerator) InitResources() error { g.Resources = append(g.Resources, r) } } - return p.Err() + return nil } diff --git a/providers/aws/cloudformation.go b/providers/aws/cloudformation.go index d722cf585..6ced46610 100644 --- a/providers/aws/cloudformation.go +++ b/providers/aws/cloudformation.go @@ -18,8 +18,8 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) var cloudFormationAllowEmptyValues = []string{"tags."} @@ -33,11 +33,15 @@ func (g *CloudFormationGenerator) InitResources() error { if e != nil { return e } - svc := cloudformation.New(config) - p := cloudformation.NewListStacksPaginator(svc.ListStacksRequest(&cloudformation.ListStacksInput{})) - for p.Next(context.Background()) { - for _, stackSummary := range p.CurrentPage().StackSummaries { - if stackSummary.StackStatus == cloudformation.StackStatusDeleteComplete { + svc := cloudformation.NewFromConfig(config) + p := cloudformation.NewListStacksPaginator(svc, &cloudformation.ListStacksInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, stackSummary := range page.StackSummaries { + if stackSummary.StackStatus == types.StackStatusDeleteComplete { continue } g.Resources = append(g.Resources, terraformutils.NewSimpleResource( @@ -49,15 +53,12 @@ func (g *CloudFormationGenerator) InitResources() error { )) } } - if err := p.Err(); err != nil { - return err - } - stackSets, err := svc.ListStackSetsRequest(&cloudformation.ListStackSetsInput{}).Send(context.Background()) + stackSets, err := svc.ListStackSets(context.TODO(), &cloudformation.ListStackSetsInput{}) if err != nil { return err } for _, stackSetSummary := range stackSets.Summaries { - if stackSetSummary.Status == cloudformation.StackSetStatusDeleted { + if stackSetSummary.Status == types.StackSetStatusDeleted { continue } g.Resources = append(g.Resources, terraformutils.NewSimpleResource( @@ -68,14 +69,14 @@ func (g *CloudFormationGenerator) InitResources() error { cloudFormationAllowEmptyValues, )) - stackSetInstances, err := svc.ListStackInstancesRequest(&cloudformation.ListStackInstancesInput{ + stackSetInstances, err := svc.ListStackInstances(context.TODO(), &cloudformation.ListStackInstancesInput{ StackSetName: stackSetSummary.StackSetName, - }).Send(context.Background()) + }) if err != nil { return err } for _, stackSetI := range stackSetInstances.Summaries { - id := aws.StringValue(stackSetI.StackSetId) + "," + aws.StringValue(stackSetI.Account) + "," + aws.StringValue(stackSetI.Region) + id := StringValue(stackSetI.StackSetId) + "," + StringValue(stackSetI.Account) + "," + StringValue(stackSetI.Region) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( id, diff --git a/providers/aws/cloudhsm.go b/providers/aws/cloudhsm.go new file mode 100644 index 000000000..3ff973bb2 --- /dev/null +++ b/providers/aws/cloudhsm.go @@ -0,0 +1,70 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/cloudhsmv2" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var cloudHsmAllowEmptyValues = []string{"tags."} + +type CloudHsmGenerator struct { + AWSService +} + +func (g *CloudHsmGenerator) InitResources() error { + config, e := g.generateConfig() + if e != nil { + return e + } + svc := cloudhsmv2.NewFromConfig(config) + + p := cloudhsmv2.NewDescribeClustersPaginator(svc, &cloudhsmv2.DescribeClustersInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, cluster := range page.Clusters { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(cluster.ClusterId), + StringValue(cluster.ClusterId), + "aws_cloudhsm_v2_cluster", + "aws", + cloudHsmAllowEmptyValues, + )) + + for _, hsm := range cluster.Hsms { + g.Resources = append(g.Resources, terraformutils.NewResource( + StringValue(hsm.HsmId), + StringValue(hsm.HsmId), + "aws_cloudhsm_v2_hsm", + "aws", + map[string]string{ + "cluster_id": StringValue(hsm.ClusterId), + }, + cloudHsmAllowEmptyValues, + map[string]interface{}{}, + )) + + } + } + } + return nil +} diff --git a/providers/aws/cloudtrail.go b/providers/aws/cloudtrail.go index d7afeadd2..9de73cd02 100644 --- a/providers/aws/cloudtrail.go +++ b/providers/aws/cloudtrail.go @@ -18,8 +18,8 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/cloudtrail" + "github.com/aws/aws-sdk-go-v2/service/cloudtrail/types" ) var cloudtrailAllowEmptyValues = []string{"tags."} @@ -28,10 +28,10 @@ type CloudTrailGenerator struct { AWSService } -func (g *CloudTrailGenerator) createResources(trailList []cloudtrail.Trail) []terraformutils.Resource { +func (g *CloudTrailGenerator) createResources(trailList []types.Trail) []terraformutils.Resource { var resources []terraformutils.Resource for _, trail := range trailList { - resourceName := aws.StringValue(trail.Name) + resourceName := StringValue(trail.Name) resources = append(resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -47,8 +47,8 @@ func (g *CloudTrailGenerator) InitResources() error { if e != nil { return e } - svc := cloudtrail.New(config) - output, err := svc.DescribeTrailsRequest(&cloudtrail.DescribeTrailsInput{}).Send(context.Background()) + svc := cloudtrail.NewFromConfig(config) + output, err := svc.DescribeTrails(context.TODO(), &cloudtrail.DescribeTrailsInput{}) if err != nil { return err } diff --git a/providers/aws/cloudwatch.go b/providers/aws/cloudwatch.go index c74ae2810..3cb340860 100644 --- a/providers/aws/cloudwatch.go +++ b/providers/aws/cloudwatch.go @@ -34,7 +34,7 @@ func (g *CloudWatchGenerator) InitResources() error { return e } - cloudwatchSvc := cloudwatch.New(config) + cloudwatchSvc := cloudwatch.NewFromConfig(config) err := g.createMetricAlarms(cloudwatchSvc) if err != nil { return err @@ -44,7 +44,7 @@ func (g *CloudWatchGenerator) InitResources() error { return err } - cloudwatcheventsSvc := cloudwatchevents.New(config) + cloudwatcheventsSvc := cloudwatchevents.NewFromConfig(config) err = g.createRules(cloudwatcheventsSvc) if err != nil { return err @@ -56,9 +56,9 @@ func (g *CloudWatchGenerator) InitResources() error { func (g *CloudWatchGenerator) createMetricAlarms(cloudwatchSvc *cloudwatch.Client) error { var nextToken *string for { - output, err := cloudwatchSvc.DescribeAlarmsRequest(&cloudwatch.DescribeAlarmsInput{ + output, err := cloudwatchSvc.DescribeAlarms(context.TODO(), &cloudwatch.DescribeAlarmsInput{ NextToken: nextToken, - }).Send(context.Background()) + }) if err != nil { return err } @@ -81,9 +81,9 @@ func (g *CloudWatchGenerator) createMetricAlarms(cloudwatchSvc *cloudwatch.Clien func (g *CloudWatchGenerator) createDashboards(cloudwatchSvc *cloudwatch.Client) error { var nextToken *string for { - output, err := cloudwatchSvc.ListDashboardsRequest(&cloudwatch.ListDashboardsInput{ + output, err := cloudwatchSvc.ListDashboards(context.TODO(), &cloudwatch.ListDashboardsInput{ NextToken: nextToken, - }).Send(context.Background()) + }) if err != nil { return err } @@ -106,9 +106,9 @@ func (g *CloudWatchGenerator) createDashboards(cloudwatchSvc *cloudwatch.Client) func (g *CloudWatchGenerator) createRules(cloudwatcheventsSvc *cloudwatchevents.Client) error { var listRulesNextToken *string for { - output, err := cloudwatcheventsSvc.ListRulesRequest(&cloudwatchevents.ListRulesInput{ + output, err := cloudwatcheventsSvc.ListRules(context.TODO(), &cloudwatchevents.ListRulesInput{ NextToken: listRulesNextToken, - }).Send(context.Background()) + }) if err != nil { return err } @@ -122,10 +122,10 @@ func (g *CloudWatchGenerator) createRules(cloudwatcheventsSvc *cloudwatchevents. var listTargetsNextToken *string for { - targetResponse, err := cloudwatcheventsSvc.ListTargetsByRuleRequest(&cloudwatchevents.ListTargetsByRuleInput{ + targetResponse, err := cloudwatcheventsSvc.ListTargetsByRule(context.TODO(), &cloudwatchevents.ListTargetsByRuleInput{ Rule: rule.Name, NextToken: listTargetsNextToken, - }).Send(context.Background()) + }) if err != nil { return err } diff --git a/providers/aws/codebuild.go b/providers/aws/codebuild.go index 00999c089..8887566ea 100644 --- a/providers/aws/codebuild.go +++ b/providers/aws/codebuild.go @@ -27,29 +27,26 @@ type CodeBuildGenerator struct { AWSService } -func (g *CodeBuildGenerator) createResources(projectList []string) []terraformutils.Resource { - var resources []terraformutils.Resource - for _, project := range projectList { - resources = append(resources, terraformutils.NewSimpleResource( - project, - project, - "aws_codebuild_project", - "aws", - codebuildAllowEmptyValues)) - } - return resources -} - func (g *CodeBuildGenerator) InitResources() error { config, e := g.generateConfig() if e != nil { return e } - svc := codebuild.New(config) - output, err := svc.ListProjectsRequest(&codebuild.ListProjectsInput{}).Send(context.Background()) - if err != nil { - return err + svc := codebuild.NewFromConfig(config) + p := codebuild.NewListProjectsPaginator(svc, &codebuild.ListProjectsInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, project := range page.Projects { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + project, + project, + "aws_codebuild_project", + "aws", + codebuildAllowEmptyValues)) + } } - g.Resources = g.createResources(output.Projects) return nil } diff --git a/providers/aws/codecommit.go b/providers/aws/codecommit.go index aa573c572..9cba5728f 100644 --- a/providers/aws/codecommit.go +++ b/providers/aws/codecommit.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/codecommit" ) @@ -33,12 +32,16 @@ func (g *CodeCommitGenerator) InitResources() error { if e != nil { return e } - svc := codecommit.New(config) - p := codecommit.NewListRepositoriesPaginator(svc.ListRepositoriesRequest(&codecommit.ListRepositoriesInput{})) + svc := codecommit.NewFromConfig(config) + p := codecommit.NewListRepositoriesPaginator(svc, &codecommit.ListRepositoriesInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, repository := range p.CurrentPage().Repositories { - resourceName := aws.StringValue(repository.RepositoryName) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, repository := range page.Repositories { + resourceName := StringValue(repository.RepositoryName) resources = append(resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -48,5 +51,5 @@ func (g *CodeCommitGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/codedeploy.go b/providers/aws/codedeploy.go index 8a31696e5..f70a9ac8b 100644 --- a/providers/aws/codedeploy.go +++ b/providers/aws/codedeploy.go @@ -33,11 +33,15 @@ func (g *CodeDeployGenerator) InitResources() error { if e != nil { return e } - svc := codedeploy.New(config) - p := codedeploy.NewListApplicationsPaginator(svc.ListApplicationsRequest(&codedeploy.ListApplicationsInput{})) + svc := codedeploy.NewFromConfig(config) + p := codedeploy.NewListApplicationsPaginator(svc, &codedeploy.ListApplicationsInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, application := range p.CurrentPage().Applications { + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, application := range page.Applications { resources = append(resources, terraformutils.NewSimpleResource( fmt.Sprintf(":%s", application), application, @@ -47,5 +51,5 @@ func (g *CodeDeployGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/codepipeline.go b/providers/aws/codepipeline.go index ad817de1c..4a6ea3a44 100644 --- a/providers/aws/codepipeline.go +++ b/providers/aws/codepipeline.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/codepipeline" ) @@ -29,10 +28,14 @@ type CodePipelineGenerator struct { } func (g *CodePipelineGenerator) loadPipelines(svc *codepipeline.Client) error { - p := codepipeline.NewListPipelinesPaginator(svc.ListPipelinesRequest(&codepipeline.ListPipelinesInput{})) - for p.Next(context.Background()) { - for _, pipeline := range p.CurrentPage().Pipelines { - resourceName := aws.StringValue(pipeline.Name) + p := codepipeline.NewListPipelinesPaginator(svc, &codepipeline.ListPipelinesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, pipeline := range page.Pipelines { + resourceName := StringValue(pipeline.Name) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -41,14 +44,18 @@ func (g *CodePipelineGenerator) loadPipelines(svc *codepipeline.Client) error { codepipelineAllowEmptyValues)) } } - return p.Err() + return nil } func (g *CodePipelineGenerator) loadWebhooks(svc *codepipeline.Client) error { - p := codepipeline.NewListWebhooksPaginator(svc.ListWebhooksRequest(&codepipeline.ListWebhooksInput{})) - for p.Next(context.Background()) { - for _, webhook := range p.CurrentPage().Webhooks { - resourceArn := aws.StringValue(webhook.Arn) + p := codepipeline.NewListWebhooksPaginator(svc, &codepipeline.ListWebhooksInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, webhook := range page.Webhooks { + resourceArn := StringValue(webhook.Arn) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceArn, resourceArn, @@ -57,7 +64,7 @@ func (g *CodePipelineGenerator) loadWebhooks(svc *codepipeline.Client) error { codepipelineAllowEmptyValues)) } } - return p.Err() + return nil } func (g *CodePipelineGenerator) InitResources() error { @@ -65,7 +72,7 @@ func (g *CodePipelineGenerator) InitResources() error { if e != nil { return e } - svc := codepipeline.New(config) + svc := codepipeline.NewFromConfig(config) if err := g.loadPipelines(svc); err != nil { return err diff --git a/providers/aws/cognito.go b/providers/aws/cognito.go index 8bfe805e8..567aed2c5 100644 --- a/providers/aws/cognito.go +++ b/providers/aws/cognito.go @@ -9,6 +9,10 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider" ) +var CognitoAllowEmptyValues = []string{"tags."} + +var CognitoAdditionalFields = map[string]interface{}{} + type CognitoGenerator struct { AWSService } @@ -16,17 +20,15 @@ type CognitoGenerator struct { const CognitoMaxResults = 60 // Required field for Cognito API func (g *CognitoGenerator) loadIdentityPools(svc *cognitoidentity.Client) error { - var nextToken *string - for { - pools, err := svc.ListIdentityPoolsRequest(&cognitoidentity.ListIdentityPoolsInput{ - NextToken: nextToken, - MaxResults: aws.Int64(CognitoMaxResults), - }).Send(context.Background()) + p := cognitoidentity.NewListIdentityPoolsPaginator(svc, &cognitoidentity.ListIdentityPoolsInput{ + MaxResults: *aws.Int32(CognitoMaxResults), + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) if err != nil { return err } - - for _, pool := range pools.IdentityPools { + for _, pool := range page.IdentityPools { var id = *pool.IdentityPoolId var resourceName = *pool.IdentityPoolName g.Resources = append(g.Resources, terraformutils.NewSimpleResource( @@ -36,22 +38,22 @@ func (g *CognitoGenerator) loadIdentityPools(svc *cognitoidentity.Client) error "aws", []string{})) } - - nextToken = pools.NextToken - if nextToken == nil { - break - } } return nil } -func (g *CognitoGenerator) loadUserPools(svc *cognitoidentityprovider.Client) error { - req := svc.ListUserPoolsRequest(&cognitoidentityprovider.ListUserPoolsInput{MaxResults: aws.Int64(CognitoMaxResults)}) - p := cognitoidentityprovider.NewListUserPoolsPaginator(req) +func (g *CognitoGenerator) loadUserPools(svc *cognitoidentityprovider.Client) ([]string, error) { + p := cognitoidentityprovider.NewListUserPoolsPaginator(svc, &cognitoidentityprovider.ListUserPoolsInput{ + MaxResults: *aws.Int32(CognitoMaxResults), + }) - for p.Next(context.Background()) { - page := p.CurrentPage() + var userPoolIds []string + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return nil, err + } for _, pool := range page.UserPools { id := *pool.Id resourceName := *pool.Name @@ -61,11 +63,40 @@ func (g *CognitoGenerator) loadUserPools(svc *cognitoidentityprovider.Client) er "aws_cognito_user_pool", "aws", []string{})) + + userPoolIds = append(userPoolIds, *pool.Id) } } + return userPoolIds, nil +} - if err := p.Err(); err != nil { - return err +func (g *CognitoGenerator) loadUserPoolClients(svc *cognitoidentityprovider.Client, userPoolIds []string) error { + for _, userPoolID := range userPoolIds { + p := cognitoidentityprovider.NewListUserPoolClientsPaginator(svc, &cognitoidentityprovider.ListUserPoolClientsInput{ + UserPoolId: aws.String(userPoolID), + MaxResults: *aws.Int32(CognitoMaxResults), + }) + + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, poolClient := range page.UserPoolClients { + id := *poolClient.ClientId + resourceName := *poolClient.ClientName + g.Resources = append(g.Resources, terraformutils.NewResource( + id, + resourceName, + "aws_cognito_user_pool_client", + "aws", + map[string]string{ + "user_pool_id": *poolClient.UserPoolId, + }, + CognitoAllowEmptyValues, + CognitoAdditionalFields)) + } + } } return nil } @@ -76,12 +107,17 @@ func (g *CognitoGenerator) InitResources() error { return e } - svcCognitoIdentity := cognitoidentity.New(config) + svcCognitoIdentity := cognitoidentity.NewFromConfig(config) if err := g.loadIdentityPools(svcCognitoIdentity); err != nil { return err } - svcCognitoIdentityProvider := cognitoidentityprovider.New(config) - if err := g.loadUserPools(svcCognitoIdentityProvider); err != nil { + svcCognitoIdentityProvider := cognitoidentityprovider.NewFromConfig(config) + + userPoolIds, err := g.loadUserPools(svcCognitoIdentityProvider) + if err != nil { + return err + } + if err = g.loadUserPoolClients(svcCognitoIdentityProvider, userPoolIds); err != nil { return err } diff --git a/providers/aws/config.go b/providers/aws/config.go index b8dda5149..5395d2d38 100644 --- a/providers/aws/config.go +++ b/providers/aws/config.go @@ -32,7 +32,7 @@ func (g *ConfigGenerator) InitResources() error { if e != nil { return e } - client := configservice.New(config) + client := configservice.NewFromConfig(config) configurationRecorderRefs, err := g.addConfigurationRecorders(client) if err != nil { @@ -47,8 +47,8 @@ func (g *ConfigGenerator) InitResources() error { } func (g *ConfigGenerator) addConfigurationRecorders(svc *configservice.Client) ([]string, error) { - configurationRecorders, err := svc.DescribeConfigurationRecordersRequest( - &configservice.DescribeConfigurationRecordersInput{}).Send(context.Background()) + configurationRecorders, err := svc.DescribeConfigurationRecorders(context.TODO(), + &configservice.DescribeConfigurationRecordersInput{}) if err != nil { return nil, err @@ -73,10 +73,11 @@ func (g *ConfigGenerator) addConfigRules(svc *configservice.Client, configuratio var nextToken *string for { - configRules, err := svc.DescribeConfigRulesRequest( + configRules, err := svc.DescribeConfigRules( + context.TODO(), &configservice.DescribeConfigRulesInput{ NextToken: nextToken, - }).Send(context.Background()) + }) if err != nil { return err @@ -104,8 +105,8 @@ func (g *ConfigGenerator) addConfigRules(svc *configservice.Client, configuratio } func (g *ConfigGenerator) addDeliveryChannels(svc *configservice.Client, configurationRecorderRefs []string) error { - deliveryChannels, err := svc.DescribeDeliveryChannelsRequest( - &configservice.DescribeDeliveryChannelsInput{}).Send(context.Background()) + deliveryChannels, err := svc.DescribeDeliveryChannels(context.TODO(), + &configservice.DescribeDeliveryChannelsInput{}) if err != nil { return err diff --git a/providers/aws/customer_gateway.go b/providers/aws/customer_gateway.go index ae741b3b6..bc6d08ca5 100644 --- a/providers/aws/customer_gateway.go +++ b/providers/aws/customer_gateway.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -29,12 +28,12 @@ type CustomerGatewayGenerator struct { AWSService } -func (CustomerGatewayGenerator) createResources(cgws *ec2.DescribeCustomerGatewaysResponse) []terraformutils.Resource { +func (CustomerGatewayGenerator) createResources(cgws *ec2.DescribeCustomerGatewaysOutput) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, cgws := range cgws.CustomerGateways { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(cgws.CustomerGatewayId), - aws.StringValue(cgws.CustomerGatewayId), + StringValue(cgws.CustomerGatewayId), + StringValue(cgws.CustomerGatewayId), "aws_customer_gateway", "aws", customerGatewayAllowEmptyValues, @@ -51,8 +50,8 @@ func (g *CustomerGatewayGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - cgws, err := svc.DescribeCustomerGatewaysRequest(&ec2.DescribeCustomerGatewaysInput{}).Send(context.Background()) + svc := ec2.NewFromConfig(config) + cgws, err := svc.DescribeCustomerGateways(context.TODO(), &ec2.DescribeCustomerGatewaysInput{}) if err != nil { return err } diff --git a/providers/aws/datapipeline.go b/providers/aws/datapipeline.go index 78a39f064..d470bc9c2 100644 --- a/providers/aws/datapipeline.go +++ b/providers/aws/datapipeline.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/datapipeline" ) @@ -33,13 +32,17 @@ func (g *DataPipelineGenerator) InitResources() error { if e != nil { return e } - svc := datapipeline.New(config) - p := datapipeline.NewListPipelinesPaginator(svc.ListPipelinesRequest(&datapipeline.ListPipelinesInput{})) + svc := datapipeline.NewFromConfig(config) + p := datapipeline.NewListPipelinesPaginator(svc, &datapipeline.ListPipelinesInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, pipeline := range p.CurrentPage().PipelineIdList { - pipelineID := aws.StringValue(pipeline.Id) - pipelineName := aws.StringValue(pipeline.Name) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, pipeline := range page.PipelineIdList { + pipelineID := StringValue(pipeline.Id) + pipelineName := StringValue(pipeline.Name) resources = append(resources, terraformutils.NewSimpleResource( pipelineID, pipelineName, @@ -49,5 +52,5 @@ func (g *DataPipelineGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/devicefarm.go b/providers/aws/devicefarm.go index f2e992dab..fb38eb99c 100644 --- a/providers/aws/devicefarm.go +++ b/providers/aws/devicefarm.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/devicefarm" ) @@ -33,13 +32,17 @@ func (g *DeviceFarmGenerator) InitResources() error { if e != nil { return e } - svc := devicefarm.New(config) - p := devicefarm.NewListProjectsPaginator(svc.ListProjectsRequest(&devicefarm.ListProjectsInput{})) + svc := devicefarm.NewFromConfig(config) + p := devicefarm.NewListProjectsPaginator(svc, &devicefarm.ListProjectsInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, project := range p.CurrentPage().Projects { - projectArn := aws.StringValue(project.Arn) - projectName := aws.StringValue(project.Name) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, project := range page.Projects { + projectArn := StringValue(project.Arn) + projectName := StringValue(project.Name) resources = append(resources, terraformutils.NewSimpleResource( projectArn, projectName, @@ -49,5 +52,5 @@ func (g *DeviceFarmGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/docdb.go b/providers/aws/docdb.go new file mode 100644 index 000000000..fdebee908 --- /dev/null +++ b/providers/aws/docdb.go @@ -0,0 +1,141 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + "log" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/aws/aws-sdk-go-v2/service/docdb" +) + +var docDBAllowEmptyValues = []string{"tags."} + +type DocDBGenerator struct { + AWSService +} + +func (g *DocDBGenerator) InitResources() error { + config, e := g.generateConfig() + if e != nil { + return e + } + svc := docdb.NewFromConfig(config) + + if err := g.getClusters(svc); err != nil { + log.Println(err) + } + + if err := g.getSubnetGroups(svc); err != nil { + log.Println(err) + } + + if err := g.getParameterGroups(svc); err != nil { + log.Println(err) + } + + return nil +} + +func (g *DocDBGenerator) getClusters(svc *docdb.Client) error { + clusterPaginator := docdb.NewDescribeDBClustersPaginator(svc, &docdb.DescribeDBClustersInput{}) + for clusterPaginator.HasMorePages() { + page, err := clusterPaginator.NextPage(context.TODO()) + if err != nil { + return err + } + + for _, cluster := range page.DBClusters { + + resourceName := StringValue(cluster.DBClusterIdentifier) + + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + resourceName, + resourceName, + "aws_docdb_cluster", + "aws", + docDBAllowEmptyValues)) + + for _, member := range cluster.DBClusterMembers { + instanceName := StringValue(member.DBInstanceIdentifier) + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + instanceName, + instanceName, + "aws_docdb_cluster_instance", + "aws", + docDBAllowEmptyValues)) + } + + } + } + + return nil +} + +func (g *DocDBGenerator) getSubnetGroups(svc *docdb.Client) error { + subnetGroupPaginator := docdb.NewDescribeDBSubnetGroupsPaginator(svc, &docdb.DescribeDBSubnetGroupsInput{}) + + for subnetGroupPaginator.HasMorePages() { + page, err := subnetGroupPaginator.NextPage(context.TODO()) + if err != nil { + return err + } + + for _, subnetGroup := range page.DBSubnetGroups { + resourceName := StringValue(subnetGroup.DBSubnetGroupName) + + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + resourceName, + resourceName, + "aws_docdb_subnet_group", + "aws", + docDBAllowEmptyValues)) + + } + } + + return nil +} + +func (g *DocDBGenerator) getParameterGroups(svc *docdb.Client) error { + parameterGroupPaginator := docdb.NewDescribeDBClusterParameterGroupsPaginator(svc, &docdb.DescribeDBClusterParameterGroupsInput{}) + + for parameterGroupPaginator.HasMorePages() { + page, err := parameterGroupPaginator.NextPage(context.TODO()) + if err != nil { + return err + } + + for _, parameterGroup := range page.DBClusterParameterGroups { + resourceName := StringValue(parameterGroup.DBClusterParameterGroupName) + + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + resourceName, + resourceName, + "aws_docdb_cluster_parameter_group", + "aws", + docDBAllowEmptyValues)) + + } + } + + return nil +} + +// PostConvertHook for add policy json as heredoc +func (g *DocDBGenerator) PostConvertHook() error { + return nil +} diff --git a/providers/aws/dynamodb.go b/providers/aws/dynamodb.go index 99077e8e9..88d8df893 100644 --- a/providers/aws/dynamodb.go +++ b/providers/aws/dynamodb.go @@ -32,10 +32,14 @@ func (g *DynamoDbGenerator) InitResources() error { if e != nil { return e } - svc := dynamodb.New(config) - p := dynamodb.NewListTablesPaginator(svc.ListTablesRequest(&dynamodb.ListTablesInput{})) - for p.Next(context.Background()) { - for _, tableName := range p.CurrentPage().TableNames { + svc := dynamodb.NewFromConfig(config) + p := dynamodb.NewListTablesPaginator(svc, &dynamodb.ListTablesInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, tableName := range page.TableNames { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( tableName, tableName, @@ -45,7 +49,7 @@ func (g *DynamoDbGenerator) InitResources() error { )) } } - return p.Err() + return nil } func (g *DynamoDbGenerator) PostConvertHook() error { diff --git a/providers/aws/ebs.go b/providers/aws/ebs.go index fe283916f..857a5569e 100644 --- a/providers/aws/ebs.go +++ b/providers/aws/ebs.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) var ebsAllowEmptyValues = []string{"tags."} @@ -41,51 +42,72 @@ func (g *EbsGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - var filters []ec2.Filter + svc := ec2.NewFromConfig(config) + var filters []types.Filter for _, filter := range g.Filter { if strings.HasPrefix(filter.FieldPath, "tags.") && filter.IsApplicable("ebs_volume") { - filters = append(filters, ec2.Filter{ + filters = append(filters, types.Filter{ Name: aws.String("tag:" + strings.TrimPrefix(filter.FieldPath, "tags.")), Values: filter.AcceptableValues, }) } } - p := ec2.NewDescribeVolumesPaginator(svc.DescribeVolumesRequest(&ec2.DescribeVolumesInput{ + p := ec2.NewDescribeVolumesPaginator(svc, &ec2.DescribeVolumesInput{ Filters: filters, - })) - for p.Next(context.Background()) { - for _, volume := range p.CurrentPage().Volumes { - g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(volume.VolumeId), - aws.StringValue(volume.VolumeId), - "aws_ebs_volume", - "aws", - ebsAllowEmptyValues, - )) + }) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, volume := range page.Volumes { + isRootDevice := false // Let's leave root device configuration to be done in ec2_instance resources for _, attachment := range volume.Attachments { - if attachment.State == ec2.VolumeAttachmentStateAttached { - attachmentID := g.volumeAttachmentID( - aws.StringValue(attachment.Device), - aws.StringValue(attachment.VolumeId), - aws.StringValue(attachment.InstanceId)) - g.Resources = append(g.Resources, terraformutils.NewResource( - attachmentID, - aws.StringValue(attachment.InstanceId)+":"+aws.StringValue(attachment.Device), - "aws_volume_attachment", - "aws", - map[string]string{ - "device_name": aws.StringValue(attachment.Device), - "volume_id": aws.StringValue(attachment.VolumeId), - "instance_id": aws.StringValue(attachment.InstanceId), - }, - []string{}, - map[string]interface{}{}, - )) + instances, _ := svc.DescribeInstances(context.TODO(), &ec2.DescribeInstancesInput{ + InstanceIds: []string{StringValue(attachment.InstanceId)}, + }) + for _, reservation := range instances.Reservations { + for _, instance := range reservation.Instances { + if StringValue(instance.RootDeviceName) == StringValue(attachment.Device) { + isRootDevice = true + } + } + } + } + + if !isRootDevice { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(volume.VolumeId), + StringValue(volume.VolumeId), + "aws_ebs_volume", + "aws", + ebsAllowEmptyValues, + )) + + for _, attachment := range volume.Attachments { + if attachment.State == types.VolumeAttachmentStateAttached { + attachmentID := g.volumeAttachmentID( + StringValue(attachment.Device), + StringValue(attachment.VolumeId), + StringValue(attachment.InstanceId)) + g.Resources = append(g.Resources, terraformutils.NewResource( + attachmentID, + StringValue(attachment.InstanceId)+":"+StringValue(attachment.Device), + "aws_volume_attachment", + "aws", + map[string]string{ + "device_name": StringValue(attachment.Device), + "volume_id": StringValue(attachment.VolumeId), + "instance_id": StringValue(attachment.InstanceId), + }, + []string{}, + map[string]interface{}{}, + )) + } } } } } - return p.Err() + return nil } diff --git a/providers/aws/ec2.go b/providers/aws/ec2.go index 3370250e5..112c7de6c 100644 --- a/providers/aws/ec2.go +++ b/providers/aws/ec2.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) var ec2AllowEmptyValues = []string{"tags."} @@ -35,39 +36,43 @@ func (g *Ec2Generator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - var filters []ec2.Filter + svc := ec2.NewFromConfig(config) + var filters []types.Filter for _, filter := range g.Filter { if strings.HasPrefix(filter.FieldPath, "tags.") && filter.IsApplicable("instance") { - filters = append(filters, ec2.Filter{ + filters = append(filters, types.Filter{ Name: aws.String("tag:" + strings.TrimPrefix(filter.FieldPath, "tags.")), Values: filter.AcceptableValues, }) } } - p := ec2.NewDescribeInstancesPaginator(svc.DescribeInstancesRequest(&ec2.DescribeInstancesInput{ + p := ec2.NewDescribeInstancesPaginator(svc, &ec2.DescribeInstancesInput{ Filters: filters, - })) - for p.Next(context.Background()) { - for _, reservation := range p.CurrentPage().Reservations { + }) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, reservation := range page.Reservations { for _, instance := range reservation.Instances { name := "" for _, tag := range instance.Tags { - if strings.ToLower(aws.StringValue(tag.Key)) == "name" { - name = aws.StringValue(tag.Value) + if strings.ToLower(*tag.Key) == "name" { + name = *tag.Value } } - attr, err := svc.DescribeInstanceAttributeRequest(&ec2.DescribeInstanceAttributeInput{ - Attribute: ec2.InstanceAttributeNameUserData, + attr, err := svc.DescribeInstanceAttribute(context.TODO(), &ec2.DescribeInstanceAttributeInput{ + Attribute: types.InstanceAttributeNameUserData, InstanceId: instance.InstanceId, - }).Send(context.Background()) + }) userDataBase64 := "" if err == nil && attr.UserData != nil && attr.UserData.Value != nil { - userDataBase64 = aws.StringValue(attr.UserData.Value) + userDataBase64 = *attr.UserData.Value } r := terraformutils.NewResource( - aws.StringValue(instance.InstanceId), - aws.StringValue(instance.InstanceId)+"_"+name, + *instance.InstanceId, + *instance.InstanceId+"_"+name, "aws_instance", "aws", map[string]string{ @@ -81,5 +86,22 @@ func (g *Ec2Generator) InitResources() error { } } } - return p.Err() + return nil +} + +func (g *Ec2Generator) PostConvertHook() error { + for _, r := range g.Resources { + if r.InstanceInfo.Type != "aws_instance" { + continue + } + rootDeviceVolumeType := r.InstanceState.Attributes["root_block_device.0.volume_type"] + if !(rootDeviceVolumeType == "io1" || rootDeviceVolumeType == "io2" || rootDeviceVolumeType == "gp3") { + delete(r.Item["root_block_device"].([]interface{})[0].(map[string]interface{}), "iops") + } + if rootDeviceVolumeType != "gp3" { + delete(r.Item["root_block_device"].([]interface{})[0].(map[string]interface{}), "throughput") + } + } + + return nil } diff --git a/providers/aws/ecr.go b/providers/aws/ecr.go index eca9a373b..4d68eb142 100644 --- a/providers/aws/ecr.go +++ b/providers/aws/ecr.go @@ -16,9 +16,11 @@ package aws import ( "context" + "fmt" - "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/ecr" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" ) var ecrAllowEmptyValues = []string{"tags."} @@ -32,30 +34,70 @@ func (g *EcrGenerator) InitResources() error { if e != nil { return e } - svc := ecr.New(config) - p := ecr.NewDescribeRepositoriesPaginator(svc.DescribeRepositoriesRequest(&ecr.DescribeRepositoriesInput{})) - for p.Next(context.Background()) { - for _, repository := range p.CurrentPage().Repositories { + svc := ecr.NewFromConfig(config) + + p := ecr.NewDescribeRepositoriesPaginator(svc, &ecr.DescribeRepositoriesInput{}) + for p.HasMorePages() { + page, e := p.NextPage(context.TODO()) + if e != nil { + return e + } + for _, repository := range page.Repositories { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *repository.RepositoryName, *repository.RepositoryName, "aws_ecr_repository", "aws", ecrAllowEmptyValues)) - g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - *repository.RepositoryName, - *repository.RepositoryName, - "aws_ecr_repository_policy", - "aws", - ecrAllowEmptyValues)) - g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - *repository.RepositoryName, - *repository.RepositoryName, - "aws_ecr_lifecycle_policy", - "aws", - ecrAllowEmptyValues)) + + _, err := svc.GetRepositoryPolicy(context.TODO(), &ecr.GetRepositoryPolicyInput{ + RepositoryName: repository.RepositoryName, + RegistryId: repository.RegistryId, + }) + if err == nil { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + *repository.RepositoryName, + *repository.RepositoryName, + "aws_ecr_repository_policy", + "aws", + ecrAllowEmptyValues)) + } + + _, err = svc.GetLifecyclePolicy(context.TODO(), &ecr.GetLifecyclePolicyInput{ + RepositoryName: repository.RepositoryName, + RegistryId: repository.RegistryId, + }) + if err == nil { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + *repository.RepositoryName, + *repository.RepositoryName, + "aws_ecr_lifecycle_policy", + "aws", + ecrAllowEmptyValues)) + } + } + } + return nil +} + +func (g *EcrGenerator) PostConvertHook() error { + for i, resource := range g.Resources { + if resource.InstanceInfo.Type == "aws_ecr_repository_policy" { + if val, ok := g.Resources[i].Item["policy"]; ok { + policy := g.escapeAwsInterpolation(val.(string)) + g.Resources[i].Item["policy"] = fmt.Sprintf(`< 0 { + request = kinesis.ListStreamsInput{ + ExclusiveStartStreamName: &results.StreamNames[len(results.StreamNames)-1], + } + } } - return p.Err() + return nil } diff --git a/providers/aws/kms.go b/providers/aws/kms.go index c8b8a435b..64884a374 100644 --- a/providers/aws/kms.go +++ b/providers/aws/kms.go @@ -16,10 +16,11 @@ package aws import ( "context" - "strings" + "log" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/kms/types" ) var kmsAllowEmptyValues = []string{"tags."} @@ -33,56 +34,103 @@ func (g *KmsGenerator) InitResources() error { if e != nil { return e } - client := kms.New(config) + client := kms.NewFromConfig(config) - err, aliases := g.addAliases(client) + err := g.addKeys(client) if err != nil { return err } - err = g.addKeys(client, aliases) + err = g.addAliases(client) return err } -func (g *KmsGenerator) addKeys(client *kms.Client, aliases map[string]string) error { - p := kms.NewListKeysPaginator(client.ListKeysRequest(&kms.ListKeysInput{})) - for p.Next(context.Background()) { - for _, key := range p.CurrentPage().Keys { - if strings.HasPrefix(aliases[*key.KeyId], "alias/aws/") { +func (g *KmsGenerator) addKeys(client *kms.Client) error { + p := kms.NewListKeysPaginator(client, &kms.ListKeysInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, key := range page.Keys { + keyDescription, err := client.DescribeKey(context.TODO(), &kms.DescribeKeyInput{ + KeyId: key.KeyId, + }) + if err != nil { + log.Println(err) continue } - resource := terraformutils.NewResource( - *key.KeyId, - *key.KeyId, - "aws_kms_key", - "aws", - map[string]string{ - "key_id": *key.KeyId, - }, - kmsAllowEmptyValues, - map[string]interface{}{}, - ) - resource.SlowQueryRequired = true - g.Resources = append(g.Resources, resource) + if keyDescription.KeyMetadata.KeyManager == types.KeyManagerTypeCustomer { + resource := terraformutils.NewResource( + *key.KeyId, + *key.KeyId, + "aws_kms_key", + "aws", + map[string]string{ + "key_id": *key.KeyId, + }, + kmsAllowEmptyValues, + map[string]interface{}{}, + ) + resource.SlowQueryRequired = true + g.Resources = append(g.Resources, resource) + + g.addGrants(key.KeyId, client) + } } } - return p.Err() + return nil } -func (g *KmsGenerator) addAliases(client *kms.Client) (error, map[string]string) { - p := kms.NewListAliasesPaginator(client.ListAliasesRequest(&kms.ListAliasesInput{})) - aliases := make(map[string]string) - for p.Next(context.Background()) { - for _, alias := range p.CurrentPage().Aliases { - if strings.HasPrefix(*alias.AliasName, "alias/aws/") { - if alias.TargetKeyId != nil { - aliases[*alias.TargetKeyId] = *alias.AliasName - } +func (g *KmsGenerator) addAliases(client *kms.Client) error { + p := kms.NewListAliasesPaginator(client, &kms.ListAliasesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, alias := range page.Aliases { + if alias.TargetKeyId == nil { continue } + keyDescription, err := client.DescribeKey(context.TODO(), &kms.DescribeKeyInput{ + KeyId: alias.TargetKeyId, + }) + if err != nil { + log.Println(err) + continue + } + if keyDescription.KeyMetadata.KeyManager == types.KeyManagerTypeCustomer { + resource := terraformutils.NewSimpleResource( + *alias.AliasName, + *alias.AliasName, + "aws_kms_alias", + "aws", + kmsAllowEmptyValues, + ) + resource.SlowQueryRequired = true + g.Resources = append(g.Resources, resource) + } + } + } + return nil +} + +func (g *KmsGenerator) addGrants(keyID *string, client *kms.Client) { + p := kms.NewListGrantsPaginator(client, &kms.ListGrantsInput{ + KeyId: keyID, + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + log.Println(err) + return + } + for _, grant := range page.Grants { + grantID := *grant.KeyId + ":" + *grant.GrantId resource := terraformutils.NewSimpleResource( - *alias.AliasName, - *alias.AliasName, - "aws_kms_alias", + grantID, + grantID, + "aws_kms_grant", "aws", kmsAllowEmptyValues, ) @@ -90,5 +138,4 @@ func (g *KmsGenerator) addAliases(client *kms.Client) (error, map[string]string) g.Resources = append(g.Resources, resource) } } - return p.Err(), aliases } diff --git a/providers/aws/lambda.go b/providers/aws/lambda.go index 9169d36ac..6852f3835 100644 --- a/providers/aws/lambda.go +++ b/providers/aws/lambda.go @@ -32,7 +32,7 @@ func (g *LambdaGenerator) InitResources() error { if e != nil { return e } - svc := lambda.New(config) + svc := lambda.NewFromConfig(config) err := g.addFunctions(svc) if err != nil { @@ -70,9 +70,13 @@ func (g *LambdaGenerator) PostConvertHook() error { } func (g *LambdaGenerator) addFunctions(svc *lambda.Client) error { - p := lambda.NewListFunctionsPaginator(svc.ListFunctionsRequest(&lambda.ListFunctionsInput{})) - for p.Next(context.Background()) { - for _, function := range p.CurrentPage().Functions { + p := lambda.NewListFunctionsPaginator(svc, &lambda.ListFunctionsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, function := range page.Functions { g.Resources = append(g.Resources, terraformutils.NewResource( *function.FunctionArn, *function.FunctionName, @@ -85,12 +89,16 @@ func (g *LambdaGenerator) addFunctions(svc *lambda.Client) error { map[string]interface{}{}, )) - pi := lambda.NewListFunctionEventInvokeConfigsPaginator(svc.ListFunctionEventInvokeConfigsRequest( + pi := lambda.NewListFunctionEventInvokeConfigsPaginator(svc, &lambda.ListFunctionEventInvokeConfigsInput{ FunctionName: function.FunctionName, - })) - for pi.Next(context.Background()) { - for _, functionEventInvokeConfig := range pi.CurrentPage().FunctionEventInvokeConfigs { + }) + for pi.HasMorePages() { + piage, err := pi.NextPage(context.TODO()) + if err != nil { + return err + } + for _, functionEventInvokeConfig := range piage.FunctionEventInvokeConfigs { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *function.FunctionArn, "feic_"+*functionEventInvokeConfig.FunctionArn, @@ -100,18 +108,19 @@ func (g *LambdaGenerator) addFunctions(svc *lambda.Client) error { )) } } - if err := pi.Err(); err != nil { - return err - } } } - return p.Err() + return nil } func (g *LambdaGenerator) addEventSourceMappings(svc *lambda.Client) error { - p := lambda.NewListEventSourceMappingsPaginator(svc.ListEventSourceMappingsRequest(&lambda.ListEventSourceMappingsInput{})) - for p.Next(context.Background()) { - for _, mapping := range p.CurrentPage().EventSourceMappings { + p := lambda.NewListEventSourceMappingsPaginator(svc, &lambda.ListEventSourceMappingsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, mapping := range page.EventSourceMappings { g.Resources = append(g.Resources, terraformutils.NewResource( *mapping.UUID, *mapping.UUID, @@ -126,18 +135,26 @@ func (g *LambdaGenerator) addEventSourceMappings(svc *lambda.Client) error { )) } } - return p.Err() + return nil } func (g *LambdaGenerator) addLayerVersions(svc *lambda.Client) error { - pl := lambda.NewListLayersPaginator(svc.ListLayersRequest(&lambda.ListLayersInput{})) - for pl.Next(context.Background()) { - for _, layer := range pl.CurrentPage().Layers { - pv := lambda.NewListLayerVersionsPaginator(svc.ListLayerVersionsRequest(&lambda.ListLayerVersionsInput{ + pl := lambda.NewListLayersPaginator(svc, &lambda.ListLayersInput{}) + for pl.HasMorePages() { + plage, err := pl.NextPage(context.TODO()) + if err != nil { + return err + } + for _, layer := range plage.Layers { + pv := lambda.NewListLayerVersionsPaginator(svc, &lambda.ListLayerVersionsInput{ LayerName: layer.LayerName, - })) - for pv.Next(context.Background()) { - for _, layerVersion := range pv.CurrentPage().LayerVersions { + }) + for pv.HasMorePages() { + pvage, err := pv.NextPage(context.TODO()) + if err != nil { + return err + } + for _, layerVersion := range pvage.LayerVersions { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *layerVersion.LayerVersionArn, *layerVersion.LayerVersionArn, @@ -147,10 +164,7 @@ func (g *LambdaGenerator) addLayerVersions(svc *lambda.Client) error { )) } } - if err := pv.Err(); err != nil { - return err - } } } - return pl.Err() + return nil } diff --git a/providers/aws/logs.go b/providers/aws/logs.go index 20185f07a..9ea8c37b5 100644 --- a/providers/aws/logs.go +++ b/providers/aws/logs.go @@ -19,7 +19,6 @@ import ( "strconv" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" ) @@ -29,15 +28,15 @@ type LogsGenerator struct { AWSService } -func (g *LogsGenerator) createResources(logGroups *cloudwatchlogs.DescribeLogGroupsResponse) []terraformutils.Resource { +func (g *LogsGenerator) createResources(logGroups *cloudwatchlogs.DescribeLogGroupsOutput) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, logGroup := range logGroups.LogGroups { - resourceName := aws.StringValue(logGroup.LogGroupName) + resourceName := StringValue(logGroup.LogGroupName) attributes := map[string]string{} if logGroup.RetentionInDays != nil { - attributes["retention_in_days"] = strconv.FormatInt(*logGroup.RetentionInDays, 10) + attributes["retention_in_days"] = strconv.FormatInt(int64(*logGroup.RetentionInDays), 10) } if logGroup.KmsKeyId != nil { @@ -62,13 +61,16 @@ func (g *LogsGenerator) InitResources() error { if e != nil { return e } - svc := cloudwatchlogs.New(config) + svc := cloudwatchlogs.NewFromConfig(config) - logGroups, err := svc.DescribeLogGroupsRequest(&cloudwatchlogs.DescribeLogGroupsInput{}).Send(context.Background()) - if err != nil { - return err + p := cloudwatchlogs.NewDescribeLogGroupsPaginator(svc, &cloudwatchlogs.DescribeLogGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - g.Resources = g.createResources(logGroups) return nil } diff --git a/providers/aws/media_package.go b/providers/aws/media_package.go index 64b6046ff..93b830841 100644 --- a/providers/aws/media_package.go +++ b/providers/aws/media_package.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/mediapackage" ) @@ -33,12 +32,16 @@ func (g *MediaPackageGenerator) InitResources() error { if e != nil { return e } - svc := mediapackage.New(config) - p := mediapackage.NewListChannelsPaginator(svc.ListChannelsRequest(&mediapackage.ListChannelsInput{})) + svc := mediapackage.NewFromConfig(config) + p := mediapackage.NewListChannelsPaginator(svc, &mediapackage.ListChannelsInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, channel := range p.CurrentPage().Channels { - channelID := aws.StringValue(channel.Id) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, channel := range page.Channels { + channelID := StringValue(channel.Id) resources = append(resources, terraformutils.NewSimpleResource( channelID, channelID, @@ -48,5 +51,5 @@ func (g *MediaPackageGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/media_store.go b/providers/aws/media_store.go index 239c4374e..f1e4fd77e 100644 --- a/providers/aws/media_store.go +++ b/providers/aws/media_store.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/mediastore" ) @@ -33,12 +32,16 @@ func (g *MediaStoreGenerator) InitResources() error { if e != nil { return e } - svc := mediastore.New(config) - p := mediastore.NewListContainersPaginator(svc.ListContainersRequest(&mediastore.ListContainersInput{})) + svc := mediastore.NewFromConfig(config) + p := mediastore.NewListContainersPaginator(svc, &mediastore.ListContainersInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, container := range p.CurrentPage().Containers { - containerName := aws.StringValue(container.Name) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, container := range page.Containers { + containerName := StringValue(container.Name) resources = append(resources, terraformutils.NewSimpleResource( containerName, containerName, @@ -48,5 +51,5 @@ func (g *MediaStoreGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/msk.go b/providers/aws/msk.go index f7f7c266f..3fde0d119 100644 --- a/providers/aws/msk.go +++ b/providers/aws/msk.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/kafka" ) @@ -33,13 +32,17 @@ func (g *MskGenerator) InitResources() error { if e != nil { return e } - svc := kafka.New(config) - p := kafka.NewListClustersPaginator(svc.ListClustersRequest(&kafka.ListClustersInput{})) - for p.Next(context.Background()) { - for _, clusterInfo := range p.CurrentPage().ClusterInfoList { + svc := kafka.NewFromConfig(config) + p := kafka.NewListClustersPaginator(svc, &kafka.ListClustersInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, clusterInfo := range page.ClusterInfoList { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(clusterInfo.ClusterArn), - aws.StringValue(clusterInfo.ClusterName), + StringValue(clusterInfo.ClusterArn), + StringValue(clusterInfo.ClusterName), "aws_msk_cluster", "aws", mskAllowEmptyValues, @@ -47,7 +50,7 @@ func (g *MskGenerator) InitResources() error { } } - return p.Err() + return nil } func (g *MskGenerator) PostConvertHook() error { diff --git a/providers/aws/nacl.go b/providers/aws/nacl.go index fe1b52a83..798f468c0 100644 --- a/providers/aws/nacl.go +++ b/providers/aws/nacl.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -32,8 +31,8 @@ func (NaclGenerator) createResources(nacls *ec2.DescribeNetworkAclsOutput) []ter resources := []terraformutils.Resource{} for _, nacl := range nacls.NetworkAcls { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(nacl.NetworkAclId), - aws.StringValue(nacl.NetworkAclId), + StringValue(nacl.NetworkAclId), + StringValue(nacl.NetworkAclId), "aws_network_acl", "aws", NaclAllowEmptyValues)) @@ -49,10 +48,14 @@ func (g *NaclGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - p := ec2.NewDescribeNetworkAclsPaginator(svc.DescribeNetworkAclsRequest(&ec2.DescribeNetworkAclsInput{})) - for p.Next(context.Background()) { - g.Resources = append(g.Resources, g.createResources(p.CurrentPage())...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeNetworkAclsPaginator(svc, &ec2.DescribeNetworkAclsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - return p.Err() + return nil } diff --git a/providers/aws/nat_gateway.go b/providers/aws/nat_gateway.go index fbedcc0bb..f1cfd5570 100644 --- a/providers/aws/nat_gateway.go +++ b/providers/aws/nat_gateway.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -30,11 +29,11 @@ type NatGatewayGenerator struct { } func (g *NatGatewayGenerator) createResources(ngws *ec2.DescribeNatGatewaysOutput) []terraformutils.Resource { - resources := []terraformutils.Resource{} + var resources []terraformutils.Resource for _, ngw := range ngws.NatGateways { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(ngw.NatGatewayId), - aws.StringValue(ngw.NatGatewayId), + StringValue(ngw.NatGatewayId), + StringValue(ngw.NatGatewayId), "aws_nat_gateway", "aws", ngwAllowEmptyValues, @@ -51,10 +50,14 @@ func (g *NatGatewayGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - p := ec2.NewDescribeNatGatewaysPaginator(svc.DescribeNatGatewaysRequest(&ec2.DescribeNatGatewaysInput{})) - for p.Next(context.Background()) { - g.Resources = append(g.Resources, g.createResources(p.CurrentPage())...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeNatGatewaysPaginator(svc, &ec2.DescribeNatGatewaysInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - return p.Err() + return nil } diff --git a/providers/aws/opsworks.go b/providers/aws/opsworks.go new file mode 100644 index 000000000..8c4ae30e1 --- /dev/null +++ b/providers/aws/opsworks.go @@ -0,0 +1,209 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + "github.com/aws/aws-sdk-go-v2/service/opsworks" + "github.com/aws/aws-sdk-go-v2/service/opsworks/types" + "log" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type OpsworksGenerator struct { + AWSService +} + +func (g *OpsworksGenerator) InitResources() error { + config, e := g.generateConfig() + if e != nil { + return e + } + svc := opsworks.NewFromConfig(config) + + e = g.fetchStacks(svc) + if e != nil { + return e + } + + e = g.fetchUserProfile(svc) + if e != nil { + return e + } + + return nil +} + +func (g *OpsworksGenerator) fetchApps(stackID *string, svc *opsworks.Client) error { + apps, err := svc.DescribeApps(context.TODO(), &opsworks.DescribeAppsInput{ + StackId: stackID, + }) + if err != nil { + return err + } + for _, app := range apps.Apps { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(app.AppId), + StringValue(app.AppId), + "aws_opsworks_application", + "aws", + []string{"tags."}, + )) + } + return nil +} + +func (g *OpsworksGenerator) fetchLayers(stackID *string, svc *opsworks.Client) error { + apps, err := svc.DescribeLayers(context.TODO(), &opsworks.DescribeLayersInput{ + StackId: stackID, + }) + if err != nil { + return err + } + for _, layer := range apps.Layers { + switch layer.Type { + case types.LayerTypeCustom: + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(layer.LayerId), + StringValue(layer.LayerId), + "aws_opsworks_custom_layer", + "aws", + []string{"tags."}, + )) + case types.LayerTypePhpApp: + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(layer.LayerId), + StringValue(layer.LayerId), + "aws_opsworks_php_app_layer", + "aws", + []string{"tags."}, + )) + case types.LayerTypeJavaApp: + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(layer.LayerId), + StringValue(layer.LayerId), + "aws_opsworks_java_app_layer", + "aws", + []string{"tags."}, + )) + case types.LayerTypeWeb: + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(layer.LayerId), + StringValue(layer.LayerId), + "aws_opsworks_static_web_layer", + "aws", + []string{"tags."}, + )) + } + } + return nil +} + +func (g *OpsworksGenerator) fetchInstances(stackID *string, svc *opsworks.Client) error { + apps, err := svc.DescribeInstances(context.TODO(), &opsworks.DescribeInstancesInput{ + StackId: stackID, + }) + if err != nil { + return err + } + for _, instances := range apps.Instances { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(instances.InstanceId), + StringValue(instances.InstanceId), + "aws_opsworks_instance", + "aws", + []string{"tags."}, + )) + } + return nil +} +func (g *OpsworksGenerator) fetchRdsInstances(stackID *string, svc *opsworks.Client) error { + apps, err := svc.DescribeRdsDbInstances(context.TODO(), &opsworks.DescribeRdsDbInstancesInput{ + StackId: stackID, + }) + if err != nil { + return err + } + for _, rdsDbInstance := range apps.RdsDbInstances { + g.Resources = append(g.Resources, terraformutils.NewResource( + StringValue(rdsDbInstance.RdsDbInstanceArn), + StringValue(rdsDbInstance.RdsDbInstanceArn), + "aws_opsworks_instance", + "aws", + map[string]string{ + "rds_db_instance_arn": StringValue(rdsDbInstance.RdsDbInstanceArn), + "stack_id": StringValue(stackID), + }, + []string{"tags."}, + map[string]interface{}{}, + )) + } + return nil +} + +func (g *OpsworksGenerator) fetchStacks(svc *opsworks.Client) error { + apps, err := svc.DescribeStacks(context.TODO(), &opsworks.DescribeStacksInput{}) + if err != nil { + return err + } + for _, stack := range apps.Stacks { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(stack.StackId), + StringValue(stack.StackId), + "aws_opsworks_stack", + "aws", + []string{"tags."}, + )) + + e := g.fetchApps(stack.StackId, svc) + if e != nil { + log.Println(err) + } + + e = g.fetchInstances(stack.StackId, svc) + if e != nil { + log.Println(err) + } + + e = g.fetchRdsInstances(stack.StackId, svc) + if e != nil { + log.Println(err) + } + + e = g.fetchLayers(stack.StackId, svc) + if e != nil { + log.Println(err) + } + } + return nil +} + +func (g *OpsworksGenerator) fetchUserProfile(svc *opsworks.Client) error { + apps, err := svc.DescribeUserProfiles(context.TODO(), &opsworks.DescribeUserProfilesInput{}) + if err != nil { + return err + } + for _, userProfile := range apps.UserProfiles { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(userProfile.IamUserArn), + StringValue(userProfile.IamUserArn), + "aws_opsworks_user_profile", + "aws", + []string{"tags."}, + )) + } + return nil +} diff --git a/providers/aws/organization.go b/providers/aws/organization.go index 602901420..7097f0a5c 100644 --- a/providers/aws/organization.go +++ b/providers/aws/organization.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/organizations" + "github.com/aws/aws-sdk-go-v2/service/organizations/types" ) var organizationAllowEmptyValues = []string{"tags."} @@ -31,57 +32,57 @@ type OrganizationGenerator struct { } func (g *OrganizationGenerator) traverseNode(svc *organizations.Client, parentID string) { - accountsForParent, err := svc.ListAccountsForParentRequest( - &organizations.ListAccountsForParentInput{ParentId: aws.String(parentID)}).Send(context.Background()) + accountsForParent, err := svc.ListAccountsForParent(context.TODO(), + &organizations.ListAccountsForParentInput{ParentId: aws.String(parentID)}) if err != nil { return } for _, account := range accountsForParent.Accounts { g.Resources = append(g.Resources, terraformutils.NewResource( - aws.StringValue(account.Id), - aws.StringValue(account.Name), + StringValue(account.Id), + StringValue(account.Name), "aws_organizations_organization", "aws", map[string]string{ - "id": aws.StringValue(account.Id), - "arn": aws.StringValue(account.Arn), + "id": StringValue(account.Id), + "arn": StringValue(account.Arn), }, organizationAllowEmptyValues, map[string]interface{}{}, )) g.Resources = append(g.Resources, terraformutils.NewResource( - aws.StringValue(account.Id), - aws.StringValue(account.Name), + StringValue(account.Id), + StringValue(account.Name), "aws_organizations_account", "aws", map[string]string{ - "id": aws.StringValue(account.Id), - "arn": aws.StringValue(account.Arn), + "id": StringValue(account.Id), + "arn": StringValue(account.Arn), }, organizationAllowEmptyValues, map[string]interface{}{}, )) } - unitsForParent, err := svc.ListOrganizationalUnitsForParentRequest( - &organizations.ListOrganizationalUnitsForParentInput{ParentId: aws.String(parentID)}).Send(context.Background()) + unitsForParent, err := svc.ListOrganizationalUnitsForParent(context.TODO(), + &organizations.ListOrganizationalUnitsForParentInput{ParentId: aws.String(parentID)}) if err != nil { return } for _, unit := range unitsForParent.OrganizationalUnits { g.Resources = append(g.Resources, terraformutils.NewResource( - aws.StringValue(unit.Id), - aws.StringValue(unit.Name), + StringValue(unit.Id), + StringValue(unit.Name), "aws_organizations_organizational_unit", "aws", map[string]string{ - "id": aws.StringValue(unit.Id), - "arn": aws.StringValue(unit.Arn), + "id": StringValue(unit.Id), + "arn": StringValue(unit.Arn), }, organizationAllowEmptyValues, map[string]interface{}{}, )) - g.traverseNode(svc, aws.StringValue(unit.Id)) + g.traverseNode(svc, StringValue(unit.Id)) } } @@ -90,25 +91,29 @@ func (g *OrganizationGenerator) InitResources() error { if e != nil { return e } - svc := organizations.New(config) + svc := organizations.NewFromConfig(config) - roots, err := svc.ListRootsRequest(&organizations.ListRootsInput{}).Send(context.Background()) + roots, err := svc.ListRoots(context.TODO(), &organizations.ListRootsInput{}) if err != nil { return err } for _, root := range roots.Roots { - nodeID := aws.StringValue(root.Id) + nodeID := StringValue(root.Id) g.traverseNode(svc, nodeID) } - p := organizations.NewListPoliciesPaginator(svc.ListPoliciesRequest(&organizations.ListPoliciesInput{ - Filter: organizations.PolicyTypeServiceControlPolicy, - })) - for p.Next(context.Background()) { - for _, policy := range p.CurrentPage().Policies { - policyID := aws.StringValue(policy.Id) - policyName := aws.StringValue(policy.Name) + p := organizations.NewListPoliciesPaginator(svc, &organizations.ListPoliciesInput{ + Filter: types.PolicyTypeServiceControlPolicy, + }) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, policy := range page.Policies { + policyID := StringValue(policy.Id) + policyName := StringValue(policy.Name) g.Resources = append(g.Resources, terraformutils.NewResource( policyID, policyName, @@ -116,27 +121,27 @@ func (g *OrganizationGenerator) InitResources() error { "aws", map[string]string{ "id": policyID, - "arn": aws.StringValue(policy.Arn), + "arn": StringValue(policy.Arn), }, organizationAllowEmptyValues, map[string]interface{}{}, )) - targetsForPolicy, err := svc.ListTargetsForPolicyRequest( - &organizations.ListTargetsForPolicyInput{PolicyId: policy.Id}).Send(context.Background()) + targetsForPolicy, err := svc.ListTargetsForPolicy(context.TODO(), + &organizations.ListTargetsForPolicyInput{PolicyId: policy.Id}) if err != nil { fmt.Println(err.Error()) continue } for _, target := range targetsForPolicy.Targets { g.Resources = append(g.Resources, terraformutils.NewResource( - aws.StringValue(target.TargetId)+":"+policyID, - "pa-"+aws.StringValue(target.TargetId)+":"+policyName, + StringValue(target.TargetId)+":"+policyID, + "pa-"+StringValue(target.TargetId)+":"+policyName, "aws_organizations_policy_attachment", "aws", map[string]string{ "policy_id": policyID, - "target_id": aws.StringValue(target.TargetId), + "target_id": StringValue(target.TargetId), }, organizationAllowEmptyValues, map[string]interface{}{}, @@ -145,5 +150,5 @@ func (g *OrganizationGenerator) InitResources() error { } } - return p.Err() + return nil } diff --git a/providers/aws/qldb.go b/providers/aws/qldb.go index dccb6ed87..752e760c1 100644 --- a/providers/aws/qldb.go +++ b/providers/aws/qldb.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/qldb" ) @@ -33,12 +32,16 @@ func (g *QLDBGenerator) InitResources() error { if e != nil { return e } - svc := qldb.New(config) - p := qldb.NewListLedgersPaginator(svc.ListLedgersRequest(&qldb.ListLedgersInput{})) + svc := qldb.NewFromConfig(config) + p := qldb.NewListLedgersPaginator(svc, &qldb.ListLedgersInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, ledger := range p.CurrentPage().Ledgers { - ledgerName := aws.StringValue(ledger.Name) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, ledger := range page.Ledgers { + ledgerName := StringValue(ledger.Name) resources = append(resources, terraformutils.NewSimpleResource( ledgerName, ledgerName, @@ -48,5 +51,5 @@ func (g *QLDBGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/rds.go b/providers/aws/rds.go index dc696a5ce..38416d56c 100644 --- a/providers/aws/rds.go +++ b/providers/aws/rds.go @@ -21,8 +21,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/rds" - - "github.com/aws/aws-sdk-go-v2/aws" ) var RDSAllowEmptyValues = []string{"tags."} @@ -31,11 +29,57 @@ type RDSGenerator struct { AWSService } +func (g *RDSGenerator) loadDBClusters(svc *rds.Client) error { + p := rds.NewDescribeDBClustersPaginator(svc, &rds.DescribeDBClustersInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, cluster := range page.DBClusters { + resourceName := StringValue(cluster.DBClusterIdentifier) + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + resourceName, + resourceName, + "aws_rds_cluster", + "aws", + RDSAllowEmptyValues, + )) + } + } + return nil +} + +func (g *RDSGenerator) loadDBProxies(svc *rds.Client) error { + p := rds.NewDescribeDBProxiesPaginator(svc, &rds.DescribeDBProxiesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, db := range page.DBProxies { + resourceName := StringValue(db.DBProxyName) + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + resourceName, + resourceName, + "aws_db_proxy", + "aws", + RDSAllowEmptyValues, + )) + } + } + return nil + +} func (g *RDSGenerator) loadDBInstances(svc *rds.Client) error { - p := rds.NewDescribeDBInstancesPaginator(svc.DescribeDBInstancesRequest(&rds.DescribeDBInstancesInput{})) - for p.Next(context.Background()) { - for _, db := range p.CurrentPage().DBInstances { - resourceName := aws.StringValue(db.DBInstanceIdentifier) + p := rds.NewDescribeDBInstancesPaginator(svc, &rds.DescribeDBInstancesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, db := range page.DBInstances { + resourceName := StringValue(db.DBInstanceIdentifier) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -45,14 +89,18 @@ func (g *RDSGenerator) loadDBInstances(svc *rds.Client) error { )) } } - return p.Err() + return nil } func (g *RDSGenerator) loadDBParameterGroups(svc *rds.Client) error { - p := rds.NewDescribeDBParameterGroupsPaginator(svc.DescribeDBParameterGroupsRequest(&rds.DescribeDBParameterGroupsInput{})) - for p.Next(context.Background()) { - for _, parameterGroup := range p.CurrentPage().DBParameterGroups { - resourceName := aws.StringValue(parameterGroup.DBParameterGroupName) + p := rds.NewDescribeDBParameterGroupsPaginator(svc, &rds.DescribeDBParameterGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, parameterGroup := range page.DBParameterGroups { + resourceName := StringValue(parameterGroup.DBParameterGroupName) if strings.Contains(resourceName, ".") { continue // skip default Default ParameterGroups like default.mysql5.6 } @@ -65,14 +113,18 @@ func (g *RDSGenerator) loadDBParameterGroups(svc *rds.Client) error { )) } } - return p.Err() + return nil } func (g *RDSGenerator) loadDBSubnetGroups(svc *rds.Client) error { - p := rds.NewDescribeDBSubnetGroupsPaginator(svc.DescribeDBSubnetGroupsRequest(&rds.DescribeDBSubnetGroupsInput{})) - for p.Next(context.Background()) { - for _, subnet := range p.CurrentPage().DBSubnetGroups { - resourceName := aws.StringValue(subnet.DBSubnetGroupName) + p := rds.NewDescribeDBSubnetGroupsPaginator(svc, &rds.DescribeDBSubnetGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, subnet := range page.DBSubnetGroups { + resourceName := StringValue(subnet.DBSubnetGroupName) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -82,14 +134,18 @@ func (g *RDSGenerator) loadDBSubnetGroups(svc *rds.Client) error { )) } } - return p.Err() + return nil } func (g *RDSGenerator) loadOptionGroups(svc *rds.Client) error { - p := rds.NewDescribeOptionGroupsPaginator(svc.DescribeOptionGroupsRequest(&rds.DescribeOptionGroupsInput{})) - for p.Next(context.Background()) { - for _, optionGroup := range p.CurrentPage().OptionGroupsList { - resourceName := aws.StringValue(optionGroup.OptionGroupName) + p := rds.NewDescribeOptionGroupsPaginator(svc, &rds.DescribeOptionGroupsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, optionGroup := range page.OptionGroupsList { + resourceName := StringValue(optionGroup.OptionGroupName) if strings.Contains(resourceName, ".") || strings.Contains(resourceName, ":") { continue // skip default Default OptionGroups like default.mysql5.6 } @@ -102,14 +158,18 @@ func (g *RDSGenerator) loadOptionGroups(svc *rds.Client) error { )) } } - return p.Err() + return nil } func (g *RDSGenerator) loadEventSubscription(svc *rds.Client) error { - p := rds.NewDescribeEventSubscriptionsPaginator(svc.DescribeEventSubscriptionsRequest(&rds.DescribeEventSubscriptionsInput{})) - for p.Next(context.Background()) { - for _, eventSubscription := range p.CurrentPage().EventSubscriptionsList { - resourceName := aws.StringValue(eventSubscription.CustomerAwsId) + p := rds.NewDescribeEventSubscriptionsPaginator(svc, &rds.DescribeEventSubscriptionsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, eventSubscription := range page.EventSubscriptionsList { + resourceName := StringValue(eventSubscription.CustomerAwsId) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, @@ -119,7 +179,7 @@ func (g *RDSGenerator) loadEventSubscription(svc *rds.Client) error { )) } } - return p.Err() + return nil } // Generate TerraformResources from AWS API, @@ -131,11 +191,17 @@ func (g *RDSGenerator) InitResources() error { if e != nil { return e } - svc := rds.New(config) + svc := rds.NewFromConfig(config) + if err := g.loadDBClusters(svc); err != nil { + return err + } if err := g.loadDBInstances(svc); err != nil { return err } + if err := g.loadDBProxies(svc); err != nil { + return err + } if err := g.loadDBParameterGroups(svc); err != nil { return err } @@ -155,34 +221,36 @@ func (g *RDSGenerator) InitResources() error { func (g *RDSGenerator) PostConvertHook() error { for i, r := range g.Resources { - if r.InstanceInfo.Type != "aws_db_instance" { - continue - } - for _, parameterGroup := range g.Resources { - if parameterGroup.InstanceInfo.Type != "aws_db_parameter_group" { - continue - } - if parameterGroup.InstanceState.Attributes["name"] == r.InstanceState.Attributes["parameter_group_name"] { - g.Resources[i].Item["parameter_group_name"] = "${aws_db_parameter_group." + parameterGroup.ResourceName + ".name}" - } - } + if r.InstanceInfo.Type == "aws_db_instance" || r.InstanceInfo.Type == "aws_rds_cluster" { - for _, subnet := range g.Resources { - if subnet.InstanceInfo.Type != "aws_db_subnet_group" { - continue - } - if subnet.InstanceState.Attributes["name"] == r.InstanceState.Attributes["db_subnet_group_name"] { - g.Resources[i].Item["db_subnet_group_name"] = "${aws_db_subnet_group." + subnet.ResourceName + ".name}" + for _, parameterGroup := range g.Resources { + if parameterGroup.InstanceInfo.Type != "aws_db_parameter_group" { + continue + } + if parameterGroup.InstanceState.Attributes["name"] == r.InstanceState.Attributes["parameter_group_name"] { + g.Resources[i].Item["parameter_group_name"] = "${aws_db_parameter_group." + parameterGroup.ResourceName + ".name}" + } } - } - for _, optionGroup := range g.Resources { - if optionGroup.InstanceInfo.Type != "aws_db_option_group" { - continue + for _, subnet := range g.Resources { + if subnet.InstanceInfo.Type != "aws_db_subnet_group" { + continue + } + if subnet.InstanceState.Attributes["name"] == r.InstanceState.Attributes["db_subnet_group_name"] { + g.Resources[i].Item["db_subnet_group_name"] = "${aws_db_subnet_group." + subnet.ResourceName + ".name}" + } } - if optionGroup.InstanceState.Attributes["name"] == r.InstanceState.Attributes["option_group_name"] { - g.Resources[i].Item["option_group_name"] = "${aws_db_option_group." + optionGroup.ResourceName + ".name}" + + for _, optionGroup := range g.Resources { + if optionGroup.InstanceInfo.Type != "aws_db_option_group" { + continue + } + if optionGroup.InstanceState.Attributes["name"] == r.InstanceState.Attributes["option_group_name"] { + g.Resources[i].Item["option_group_name"] = "${aws_db_option_group." + optionGroup.ResourceName + ".name}" + } } + } else { + continue } } return nil diff --git a/providers/aws/resourcegroups.go b/providers/aws/resourcegroups.go index cf526234a..d8993ee1c 100644 --- a/providers/aws/resourcegroups.go +++ b/providers/aws/resourcegroups.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resourcegroups" ) @@ -33,12 +32,16 @@ func (g *ResourceGroupsGenerator) InitResources() error { if e != nil { return e } - svc := resourcegroups.New(config) - p := resourcegroups.NewListGroupsPaginator(svc.ListGroupsRequest(&resourcegroups.ListGroupsInput{})) + svc := resourcegroups.NewFromConfig(config) + p := resourcegroups.NewListGroupsPaginator(svc, &resourcegroups.ListGroupsInput{}) var resources []terraformutils.Resource - for p.Next(context.Background()) { - for _, group := range p.CurrentPage().Groups { - groupName := aws.StringValue(group.Name) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, groupIdentifier := range page.GroupIdentifiers { + groupName := StringValue(groupIdentifier.GroupName) resources = append(resources, terraformutils.NewSimpleResource( groupName, groupName, @@ -48,5 +51,5 @@ func (g *ResourceGroupsGenerator) InitResources() error { } } g.Resources = resources - return p.Err() + return nil } diff --git a/providers/aws/route53.go b/providers/aws/route53.go index 9fdcb147d..5b0ab7219 100644 --- a/providers/aws/route53.go +++ b/providers/aws/route53.go @@ -35,18 +35,23 @@ type Route53Generator struct { } func (g *Route53Generator) createZonesResources(svc *route53.Client) []terraformutils.Resource { - resources := []terraformutils.Resource{} - p := route53.NewListHostedZonesPaginator(svc.ListHostedZonesRequest(&route53.ListHostedZonesInput{})) - for p.Next(context.Background()) { - for _, zone := range p.CurrentPage().HostedZones { - zoneID := cleanZoneID(aws.StringValue(zone.Id)) + var resources []terraformutils.Resource + p := route53.NewListHostedZonesPaginator(svc, &route53.ListHostedZonesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + log.Println(err) + return resources + } + for _, zone := range page.HostedZones { + zoneID := cleanZoneID(StringValue(zone.Id)) resources = append(resources, terraformutils.NewResource( zoneID, - zoneID+"_"+strings.TrimSuffix(aws.StringValue(zone.Name), "."), + zoneID+"_"+strings.TrimSuffix(StringValue(zone.Name), "."), "aws_route53_zone", "aws", map[string]string{ - "name": aws.StringValue(zone.Name), + "name": StringValue(zone.Name), "force_destroy": "false", }, route53AllowEmptyValues, @@ -56,42 +61,49 @@ func (g *Route53Generator) createZonesResources(svc *route53.Client) []terraform resources = append(resources, records...) } } - if err := p.Err(); err != nil { - log.Println(err) - } return resources } func (Route53Generator) createRecordsResources(svc *route53.Client, zoneID string) []terraformutils.Resource { var resources []terraformutils.Resource + var sets *route53.ListResourceRecordSetsOutput + var err error listParams := &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(zoneID), } - p := route53.NewListResourceRecordSetsPaginator(svc.ListResourceRecordSetsRequest(listParams)) - for p.Next(context.Background()) { - for _, record := range p.CurrentPage().ResourceRecordSets { - recordName := wildcardUnescape(aws.StringValue(record.Name)) - typeString, _ := record.Type.MarshalValue() + for { + sets, err = svc.ListResourceRecordSets(context.TODO(), listParams) + if err != nil { + log.Println(err) + return resources + } + for _, record := range sets.ResourceRecordSets { + recordName := wildcardUnescape(StringValue(record.Name)) + typeString := string(record.Type) resources = append(resources, terraformutils.NewResource( - fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, aws.StringValue(record.SetIdentifier)), - fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, aws.StringValue(record.SetIdentifier)), + fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, StringValue(record.SetIdentifier)), + fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, StringValue(record.SetIdentifier)), "aws_route53_record", "aws", map[string]string{ "name": strings.TrimSuffix(recordName, "."), "zone_id": zoneID, "type": typeString, - "set_identifier": aws.StringValue(record.SetIdentifier), + "set_identifier": StringValue(record.SetIdentifier), }, route53AllowEmptyValues, route53AdditionalFields, )) } - } - if err := p.Err(); err != nil { - log.Println(err) - return []terraformutils.Resource{} + + if sets.IsTruncated { + listParams.StartRecordName = sets.NextRecordName + listParams.StartRecordType = sets.NextRecordType + listParams.StartRecordIdentifier = sets.NextRecordIdentifier + } else { + break + } } return resources } @@ -103,7 +115,7 @@ func (g *Route53Generator) InitResources() error { if e != nil { return e } - svc := route53.New(config) + svc := route53.NewFromConfig(config) g.Resources = g.createZonesResources(svc) return nil diff --git a/providers/aws/route_table.go b/providers/aws/route_table.go index 6f61655eb..83eb73a1c 100644 --- a/providers/aws/route_table.go +++ b/providers/aws/route_table.go @@ -20,7 +20,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -31,30 +30,35 @@ type RouteTableGenerator struct { } func (g *RouteTableGenerator) createRouteTablesResources(svc *ec2.Client) []terraformutils.Resource { - resources := []terraformutils.Resource{} - p := ec2.NewDescribeRouteTablesPaginator(svc.DescribeRouteTablesRequest(&ec2.DescribeRouteTablesInput{})) - for p.Next(context.Background()) { - for _, table := range p.CurrentPage().RouteTables { + var resources []terraformutils.Resource + p := ec2.NewDescribeRouteTablesPaginator(svc, &ec2.DescribeRouteTablesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + log.Println(err) + return resources + } + for _, table := range page.RouteTables { // route table resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(table.RouteTableId), - aws.StringValue(table.RouteTableId), + StringValue(table.RouteTableId), + StringValue(table.RouteTableId), "aws_route_table", "aws", rtbAllowEmptyValues, )) for _, assoc := range table.Associations { - if aws.BoolValue(assoc.Main) { + if assoc.Main { // main route table association resources = append(resources, terraformutils.NewResource( - aws.StringValue(assoc.RouteTableAssociationId), - aws.StringValue(table.VpcId), + StringValue(assoc.RouteTableAssociationId), + StringValue(table.VpcId), "aws_main_route_table_association", "aws", map[string]string{ - "vpc_id": aws.StringValue(table.VpcId), - "route_table_id": aws.StringValue(table.RouteTableId), + "vpc_id": StringValue(table.VpcId), + "route_table_id": StringValue(table.RouteTableId), }, rtbAllowEmptyValues, map[string]interface{}{}, @@ -62,13 +66,13 @@ func (g *RouteTableGenerator) createRouteTablesResources(svc *ec2.Client) []terr } else { // subnet-specific route table association resources = append(resources, terraformutils.NewResource( - aws.StringValue(assoc.RouteTableAssociationId), - aws.StringValue(assoc.SubnetId), + StringValue(assoc.RouteTableAssociationId), + StringValue(assoc.SubnetId), "aws_route_table_association", "aws", map[string]string{ - "subnet_id": aws.StringValue(assoc.SubnetId), - "route_table_id": aws.StringValue(table.RouteTableId), + "subnet_id": StringValue(assoc.SubnetId), + "route_table_id": StringValue(table.RouteTableId), }, rtbAllowEmptyValues, map[string]interface{}{}, @@ -77,9 +81,6 @@ func (g *RouteTableGenerator) createRouteTablesResources(svc *ec2.Client) []terr } } } - if err := p.Err(); err != nil { - log.Println(err) - } return resources } @@ -90,7 +91,7 @@ func (g *RouteTableGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) + svc := ec2.NewFromConfig(config) g.Resources = g.createRouteTablesResources(svc) return nil diff --git a/providers/aws/s3.go b/providers/aws/s3.go index 684818221..93ba3b48f 100644 --- a/providers/aws/s3.go +++ b/providers/aws/s3.go @@ -21,8 +21,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws/awserr" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" ) @@ -38,66 +36,55 @@ type S3Generator struct { // createResources iterate on all buckets // for each bucket we check region and choose only bucket from set region // for each bucket try get bucket policy, if policy exist create additional NewTerraformResource for policy -func (g *S3Generator) createResources(config aws.Config, buckets *s3.ListBucketsResponse, region string) []terraformutils.Resource { - resources := []terraformutils.Resource{} - svc := s3.New(config) +func (g *S3Generator) createResources(config aws.Config, buckets *s3.ListBucketsOutput, region string) []terraformutils.Resource { + var resources []terraformutils.Resource + svc := s3.NewFromConfig(config) for _, bucket := range buckets.Buckets { - resourceName := aws.StringValue(bucket.Name) - location, err := svc.GetBucketLocationRequest(&s3.GetBucketLocationInput{Bucket: bucket.Name}).Send(context.Background()) + resourceName := StringValue(bucket.Name) + location, err := svc.GetBucketLocation(context.TODO(), &s3.GetBucketLocationInput{Bucket: bucket.Name}) if err != nil { log.Println(err) continue } // check if bucket in region - constraintString, _ := s3.NormalizeBucketLocation(location.LocationConstraint).MarshalValue() + constraintString := string(location.LocationConstraint) if constraintString == region { - resources = append(resources, terraformutils.NewResource( - resourceName, - resourceName, - "aws_s3_bucket", - "aws", - map[string]string{ - "force_destroy": "false", - "acl": "private", - }, - S3AllowEmptyValues, - S3AdditionalFields)) + attributes := map[string]string{ + "force_destroy": "false", + "acl": "private", + } // try get policy - _, err := svc.GetBucketPolicyRequest(&s3.GetBucketPolicyInput{ + var policy *s3.GetBucketPolicyOutput + policy, err = svc.GetBucketPolicy(context.TODO(), &s3.GetBucketPolicyInput{ Bucket: bucket.Name, - }).Send(context.Background()) + }) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchBucketPolicy" { - // Bucket without policy - continue - } - log.Println(err) - continue + if err == nil && policy.Policy != nil { + attributes["policy"] = *policy.Policy } - // if bucket policy exist create TerraformResource with bucket name as ID - resources = append(resources, terraformutils.NewSimpleResource( + resources = append(resources, terraformutils.NewResource( resourceName, resourceName, - "aws_s3_bucket_policy", + "aws_s3_bucket", "aws", - S3AllowEmptyValues)) + attributes, + S3AllowEmptyValues, + S3AdditionalFields)) } } return resources } // Generate TerraformResources from AWS API, -// from each s3 bucket create 2 TerraformResource(bucket and bucket policy) // Need bucket name as ID for terraform resource func (g *S3Generator) InitResources() error { config, e := g.generateConfig() if e != nil { return e } - svc := s3.New(config) + svc := s3.NewFromConfig(config) - buckets, err := svc.ListBucketsRequest(&s3.ListBucketsInput{}).Send(context.Background()) + buckets, err := svc.ListBuckets(context.TODO(), nil) if err != nil { return err } @@ -109,33 +96,16 @@ func (g *S3Generator) InitResources() error { // support only bucket with policy func (g *S3Generator) PostConvertHook() error { for i, resource := range g.Resources { - if resource.InstanceInfo.Type == "aws_s3_bucket_policy" { - policy := g.escapeAwsInterpolation(resource.Item["policy"].(string)) - g.Resources[i].Item["policy"] = fmt.Sprintf(`< 0 { if len(rule.IpRanges) > 0 { // we must unwind coupled CIDR IPv4 range + security group rules attributes := baseRuleAttributes(ruleType, rule, sg) @@ -155,7 +155,7 @@ func processRule(rule ec2.IpPermission, ruleType string, sg ec2.SecurityGroup, r return resources } -func baseRuleAttributes(ruleType string, rule ec2.IpPermission, sg ec2.SecurityGroup) map[string]interface{} { +func baseRuleAttributes(ruleType string, rule types.IpPermission, sg types.SecurityGroup) map[string]interface{} { attributes := map[string]interface{}{ "type": ruleType, "cidr_blocks": ipRange(rule), @@ -171,15 +171,15 @@ func baseRuleAttributes(ruleType string, rule ec2.IpPermission, sg ec2.SecurityG // Let's try to find all cycles by applying Johnson's method on the directed graph // We cannot build a line graph and move out only rules because of hashicorp/terraform#11011 -func findSgsToMoveOut(securityGroups []ec2.SecurityGroup) []string { +func findSgsToMoveOut(securityGroups []types.SecurityGroup) []string { // Vertexes are security groups, edges are rules. The task is to find correct set of rule definitions, so that we // won't have cycles sourceGraph := simplegraph.NewDirectedGraph() - idToSg := make(map[int]ec2.SecurityGroup) + idToSg := make(map[int]types.SecurityGroup) sgToIdx := make(map[string]int64) for idx, sg := range securityGroups { idToSg[idx] = sg - sgToIdx[aws.StringValue(sg.GroupId)] = int64(idx) + sgToIdx[StringValue(sg.GroupId)] = int64(idx) sourceGraph.AddNode(sourceGraph.NewNode()) } for idx, sg := range securityGroups { @@ -188,7 +188,7 @@ func findSgsToMoveOut(securityGroups []ec2.SecurityGroup) []string { for _, pair := range pairs { if pair.GroupId != nil { fromNode := sourceGraph.Node(int64(idx)) - toNode := sourceGraph.Node(sgToIdx[aws.StringValue(pair.GroupId)]) + toNode := sourceGraph.Node(sgToIdx[StringValue(pair.GroupId)]) if fromNode.ID() != toNode.ID() { sourceGraph.SetEdge(sourceGraph.NewEdge(fromNode, toNode)) } @@ -227,7 +227,7 @@ func findSgsToMoveOut(securityGroups []ec2.SecurityGroup) []string { return result } -func elementAlreadyFound(resultingSet map[string]void, v []graph.Node, idToSg map[int]ec2.SecurityGroup) bool { +func elementAlreadyFound(resultingSet map[string]void, v []graph.Node, idToSg map[int]types.SecurityGroup) bool { for k := range resultingSet { for _, vi := range v { viGroupID := *idToSg[int(vi.ID())].GroupId @@ -244,20 +244,21 @@ func (g *SecurityGenerator) InitResources() error { if err != nil { return err } - svc := ec2.New(config) - p := ec2.NewDescribeSecurityGroupsPaginator(svc.DescribeSecurityGroupsRequest(&ec2.DescribeSecurityGroupsInput{})) - var resourcesToFilter []ec2.SecurityGroup - for p.Next(context.Background()) { - resourcesToFilter = append(resourcesToFilter, p.CurrentPage().SecurityGroups...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeSecurityGroupsPaginator(svc, &ec2.DescribeSecurityGroupsInput{}) + var resourcesToFilter []types.SecurityGroup + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + resourcesToFilter = append(resourcesToFilter, page.SecurityGroups...) } sort.Slice(resourcesToFilter, func(i, j int) bool { return *resourcesToFilter[i].GroupId < *resourcesToFilter[j].GroupId }) g.Resources = g.createResources(resourcesToFilter) - if err := p.Err(); err != nil { - return err - } return nil } @@ -306,7 +307,7 @@ func (g *SecurityGenerator) sortIfExist(attribute string, ruleMap map[string]int } } -func permissionID(sgID, ruleType, groupID string, ip ec2.IpPermission) string { +func permissionID(sgID, ruleType, groupID string, ip types.IpPermission) string { var buf bytes.Buffer buf.WriteString(fmt.Sprintf("%s_%s_%s_%d_%d_", sgID, ruleType, *ip.IpProtocol, fromPort(ip), toPort(ip))) @@ -354,29 +355,29 @@ func permissionID(sgID, ruleType, groupID string, ip ec2.IpPermission) string { return idPreformatted[:len(idPreformatted)-1] } -func fromPort(ip ec2.IpPermission) int { +func fromPort(ip types.IpPermission) int { switch { case *ip.IpProtocol == "icmp": return -1 - case ip.FromPort != nil && *ip.FromPort > 0: - return int(*ip.FromPort) + case ip.FromPort > 0: + return int(ip.FromPort) default: return 0 } } -func toPort(ip ec2.IpPermission) int { +func toPort(ip types.IpPermission) int { switch { case *ip.IpProtocol == "icmp": return -1 - case ip.ToPort != nil && *ip.ToPort > 0: - return int(*ip.ToPort) + case ip.ToPort > 0: + return int(ip.ToPort) default: return 65536 } } -func ipRange(rule ec2.IpPermission) []string { +func ipRange(rule types.IpPermission) []string { result := make([]string, len(rule.IpRanges)) for idx, rule := range rule.IpRanges { result[idx] = *rule.CidrIp @@ -384,7 +385,7 @@ func ipRange(rule ec2.IpPermission) []string { return result } -func ip6Range(rule ec2.IpPermission) []string { +func ip6Range(rule types.IpPermission) []string { result := make([]string, len(rule.Ipv6Ranges)) for idx, rule := range rule.Ipv6Ranges { result[idx] = *rule.CidrIpv6 @@ -392,7 +393,7 @@ func ip6Range(rule ec2.IpPermission) []string { return result } -func prefixes(rule ec2.IpPermission) []string { +func prefixes(rule types.IpPermission) []string { result := make([]string, len(rule.PrefixListIds)) for idx, rule := range rule.PrefixListIds { result[idx] = *rule.PrefixListId diff --git a/providers/aws/sg_test.go b/providers/aws/sg_test.go index 34988340c..33b516ea2 100644 --- a/providers/aws/sg_test.go +++ b/providers/aws/sg_test.go @@ -19,11 +19,11 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) func TestEmptySgs(t *testing.T) { - var securityGroups []ec2.SecurityGroup + var securityGroups []types.SecurityGroup rulesToMoveOut := findSgsToMoveOut(securityGroups) @@ -33,11 +33,11 @@ func TestEmptySgs(t *testing.T) { } func Test1CycleReference(t *testing.T) { - sgA := ec2.SecurityGroup{ + sgA := types.SecurityGroup{ GroupId: aws.String("aaaa"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("aaaa"), }, @@ -46,7 +46,7 @@ func Test1CycleReference(t *testing.T) { {}, }, } - securityGroups := []ec2.SecurityGroup{ + securityGroups := []types.SecurityGroup{ sgA, } @@ -58,11 +58,11 @@ func Test1CycleReference(t *testing.T) { } func Test2CycleReference(t *testing.T) { - sgA := ec2.SecurityGroup{ + sgA := types.SecurityGroup{ GroupId: aws.String("aaaa"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("bbbb"), }, @@ -70,12 +70,12 @@ func Test2CycleReference(t *testing.T) { }, }, } - securityGroups := []ec2.SecurityGroup{ + securityGroups := []types.SecurityGroup{ { GroupId: aws.String("bbbb"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("aaaa"), }, @@ -95,11 +95,11 @@ func Test2CycleReference(t *testing.T) { } func TestNoCycleReference(t *testing.T) { - sgA := ec2.SecurityGroup{ + sgA := types.SecurityGroup{ GroupId: aws.String("aaaa"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("bbbb"), }, @@ -107,10 +107,10 @@ func TestNoCycleReference(t *testing.T) { }, }, } - securityGroups := []ec2.SecurityGroup{ + securityGroups := []types.SecurityGroup{ { GroupId: aws.String("bbbb"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ {}, {}, }, @@ -126,18 +126,18 @@ func TestNoCycleReference(t *testing.T) { } func Test3Cycle1CycleReference(t *testing.T) { - sgA := ec2.SecurityGroup{ + sgA := types.SecurityGroup{ GroupId: aws.String("aaaa"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("aaaa"), }, }, }, { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("bbbb"), }, @@ -145,13 +145,13 @@ func Test3Cycle1CycleReference(t *testing.T) { }, }, } - securityGroups := []ec2.SecurityGroup{ + securityGroups := []types.SecurityGroup{ sgA, { GroupId: aws.String("bbbb"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("cccc"), }, @@ -162,9 +162,9 @@ func Test3Cycle1CycleReference(t *testing.T) { }, { GroupId: aws.String("cccc"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("aaaa"), }, @@ -175,9 +175,9 @@ func Test3Cycle1CycleReference(t *testing.T) { }, { GroupId: aws.String("dddd"), - IpPermissions: []ec2.IpPermission{ + IpPermissions: []types.IpPermission{ { - UserIdGroupPairs: []ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String("aaaa"), }, diff --git a/providers/aws/sns.go b/providers/aws/sns.go index 1578544eb..8fa5d839b 100644 --- a/providers/aws/sns.go +++ b/providers/aws/sns.go @@ -21,8 +21,6 @@ import ( "strings" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/sns" ) @@ -42,32 +40,41 @@ func (g *SnsGenerator) InitResources() error { if e != nil { return e } - svc := sns.New(config) - p := sns.NewListTopicsPaginator(svc.ListTopicsRequest(&sns.ListTopicsInput{})) - for p.Next(context.Background()) { - for _, topic := range p.CurrentPage().Topics { - arnParts := strings.Split(aws.StringValue(topic.TopicArn), ":") + svc := sns.NewFromConfig(config) + p := sns.NewListTopicsPaginator(svc, &sns.ListTopicsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, topic := range page.Topics { + arnParts := strings.Split(StringValue(topic.TopicArn), ":") topicName := arnParts[len(arnParts)-1] g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(topic.TopicArn), + StringValue(topic.TopicArn), topicName, "aws_sns_topic", "aws", snsAllowEmptyValues, )) - topicSubsPage := sns.NewListSubscriptionsByTopicPaginator(svc.ListSubscriptionsByTopicRequest(&sns.ListSubscriptionsByTopicInput{ + topicSubsPage := sns.NewListSubscriptionsByTopicPaginator(svc, &sns.ListSubscriptionsByTopicInput{ TopicArn: topic.TopicArn, - })) - for topicSubsPage.Next(context.Background()) { - for _, subscription := range topicSubsPage.CurrentPage().Subscriptions { - subscriptionArnParts := strings.Split(aws.StringValue(subscription.SubscriptionArn), ":") + }) + for topicSubsPage.HasMorePages() { + topicSubsNextPage, err := topicSubsPage.NextPage(context.TODO()) + if err != nil { + log.Println(err) + continue + } + for _, subscription := range topicSubsNextPage.Subscriptions { + subscriptionArnParts := strings.Split(StringValue(subscription.SubscriptionArn), ":") subscriptionID := subscriptionArnParts[len(subscriptionArnParts)-1] - if g.isSupportedSubscription(aws.StringValue(subscription.Protocol), subscriptionID) { + if g.isSupportedSubscription(StringValue(subscription.Protocol), subscriptionID) { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(subscription.SubscriptionArn), + StringValue(subscription.SubscriptionArn), "subscription-"+subscriptionID, "aws_sns_topic_subscription", "aws", @@ -76,12 +83,9 @@ func (g *SnsGenerator) InitResources() error { } } } - if err := topicSubsPage.Err(); err != nil { - log.Println(err) - } } } - return p.Err() + return nil } // PostConvertHook for add policy json as heredoc diff --git a/providers/aws/sqs.go b/providers/aws/sqs.go index db729c8ab..559f37081 100644 --- a/providers/aws/sqs.go +++ b/providers/aws/sqs.go @@ -37,7 +37,7 @@ func (g *SqsGenerator) InitResources() error { if e != nil { return e } - svc := sqs.New(config) + svc := sqs.NewFromConfig(config) listQueuesInput := sqs.ListQueuesInput{} @@ -46,7 +46,7 @@ func (g *SqsGenerator) InitResources() error { listQueuesInput.QueueNamePrefix = aws.String(sqsPrefix) } - queuesList, err := svc.ListQueuesRequest(&listQueuesInput).Send(context.Background()) + queuesList, err := svc.ListQueues(context.TODO(), &listQueuesInput) if err != nil { return err diff --git a/providers/aws/ssm.go b/providers/aws/ssm.go new file mode 100644 index 000000000..99f2b04e1 --- /dev/null +++ b/providers/aws/ssm.go @@ -0,0 +1,55 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + + "github.com/aws/aws-sdk-go-v2/service/ssm" +) + +var ssmAllowEmptyValues = []string{"tags."} + +type SsmGenerator struct { + AWSService +} + +func (g *SsmGenerator) InitResources() error { + config, e := g.generateConfig() + if e != nil { + return e + } + svc := ssm.NewFromConfig(config) + p := ssm.NewDescribeParametersPaginator(svc, &ssm.DescribeParametersInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, parameter := range page.Parameters { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + StringValue(parameter.Name), + StringValue(parameter.Name), + "aws_ssm_parameter", + "aws", + ssmAllowEmptyValues, + )) + } + } + + return nil +} diff --git a/providers/aws/subnet.go b/providers/aws/subnet.go index e2a6a9225..c31583c9b 100644 --- a/providers/aws/subnet.go +++ b/providers/aws/subnet.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -32,8 +31,8 @@ func (SubnetGenerator) createResources(subnets *ec2.DescribeSubnetsOutput) []ter var resources []terraformutils.Resource for _, subnet := range subnets.Subnets { resource := terraformutils.NewSimpleResource( - aws.StringValue(subnet.SubnetId), - aws.StringValue(subnet.SubnetId), + StringValue(subnet.SubnetId), + StringValue(subnet.SubnetId), "aws_subnet", "aws", SubnetAllowEmptyValues, @@ -52,10 +51,14 @@ func (g *SubnetGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - p := ec2.NewDescribeSubnetsPaginator(svc.DescribeSubnetsRequest(&ec2.DescribeSubnetsInput{})) - for p.Next(context.Background()) { - g.Resources = append(g.Resources, g.createResources(p.CurrentPage())...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeSubnetsPaginator(svc, &ec2.DescribeSubnetsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - return p.Err() + return nil } diff --git a/providers/aws/swf.go b/providers/aws/swf.go index 6ad3831c0..6a4a01635 100644 --- a/providers/aws/swf.go +++ b/providers/aws/swf.go @@ -5,6 +5,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/swf" + "github.com/aws/aws-sdk-go-v2/service/swf/types" ) type SWFGenerator struct { @@ -12,16 +13,20 @@ type SWFGenerator struct { } func (g *SWFGenerator) InitResources() error { - regStatuses := []swf.RegistrationStatus{swf.RegistrationStatusRegistered, swf.RegistrationStatusDeprecated} + regStatuses := []types.RegistrationStatus{types.RegistrationStatusRegistered, types.RegistrationStatusDeprecated} config, e := g.generateConfig() if e != nil { return e } - svc := swf.New(config) + svc := swf.NewFromConfig(config) for _, status := range regStatuses { - p := swf.NewListDomainsPaginator(svc.ListDomainsRequest(&swf.ListDomainsInput{RegistrationStatus: status})) - for p.Next(context.Background()) { - for _, domain := range p.CurrentPage().DomainInfos { + p := swf.NewListDomainsPaginator(svc, &swf.ListDomainsInput{RegistrationStatus: status}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, domain := range page.DomainInfos { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( *domain.Name, *domain.Name, diff --git a/providers/aws/transit_gateway.go b/providers/aws/transit_gateway.go index f8a8a78fb..c129870a7 100644 --- a/providers/aws/transit_gateway.go +++ b/providers/aws/transit_gateway.go @@ -20,7 +20,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -31,32 +30,40 @@ type TransitGatewayGenerator struct { } func (g *TransitGatewayGenerator) getTransitGateways(svc *ec2.Client) error { - p := ec2.NewDescribeTransitGatewaysPaginator(svc.DescribeTransitGatewaysRequest(&ec2.DescribeTransitGatewaysInput{})) - for p.Next(context.Background()) { - for _, tgw := range p.CurrentPage().TransitGateways { + p := ec2.NewDescribeTransitGatewaysPaginator(svc, &ec2.DescribeTransitGatewaysInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, tgw := range page.TransitGateways { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(tgw.TransitGatewayId), - aws.StringValue(tgw.TransitGatewayId), + StringValue(tgw.TransitGatewayId), + StringValue(tgw.TransitGatewayId), "aws_ec2_transit_gateway", "aws", tgwAllowEmptyValues, )) } } - return p.Err() + return nil } func (g *TransitGatewayGenerator) getTransitGatewayRouteTables(svc *ec2.Client) error { - p := ec2.NewDescribeTransitGatewayRouteTablesPaginator(svc.DescribeTransitGatewayRouteTablesRequest(&ec2.DescribeTransitGatewayRouteTablesInput{})) - for p.Next(context.Background()) { - for _, tgwrt := range p.CurrentPage().TransitGatewayRouteTables { + p := ec2.NewDescribeTransitGatewayRouteTablesPaginator(svc, &ec2.DescribeTransitGatewayRouteTablesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, tgwrt := range page.TransitGatewayRouteTables { // Default route table are automatically created on the tgw creation - if *tgwrt.DefaultAssociationRouteTable { + if tgwrt.DefaultAssociationRouteTable { continue } else { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(tgwrt.TransitGatewayRouteTableId), - aws.StringValue(tgwrt.TransitGatewayRouteTableId), + StringValue(tgwrt.TransitGatewayRouteTableId), + StringValue(tgwrt.TransitGatewayRouteTableId), "aws_ec2_transit_gateway_route_table", "aws", tgwAllowEmptyValues, @@ -64,23 +71,27 @@ func (g *TransitGatewayGenerator) getTransitGatewayRouteTables(svc *ec2.Client) } } } - return p.Err() + return nil } func (g *TransitGatewayGenerator) getTransitGatewayVpcAttachments(svc *ec2.Client) error { - p := ec2.NewDescribeTransitGatewayVpcAttachmentsPaginator(svc.DescribeTransitGatewayVpcAttachmentsRequest(&ec2.DescribeTransitGatewayVpcAttachmentsInput{})) - for p.Next(context.Background()) { - for _, tgwa := range p.CurrentPage().TransitGatewayVpcAttachments { + p := ec2.NewDescribeTransitGatewayVpcAttachmentsPaginator(svc, &ec2.DescribeTransitGatewayVpcAttachmentsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, tgwa := range page.TransitGatewayVpcAttachments { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - aws.StringValue(tgwa.TransitGatewayAttachmentId), - aws.StringValue(tgwa.TransitGatewayAttachmentId), + StringValue(tgwa.TransitGatewayAttachmentId), + StringValue(tgwa.TransitGatewayAttachmentId), "aws_ec2_transit_gateway_vpc_attachment", "aws", tgwAllowEmptyValues, )) } } - return p.Err() + return nil } // Generate TerraformResources from AWS API, @@ -91,7 +102,7 @@ func (g *TransitGatewayGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) + svc := ec2.NewFromConfig(config) g.Resources = []terraformutils.Resource{} err := g.getTransitGateways(svc) if err != nil { diff --git a/providers/aws/vgw.go b/providers/aws/vgw.go index 354b305a8..be2a9b9d6 100644 --- a/providers/aws/vgw.go +++ b/providers/aws/vgw.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -29,12 +28,12 @@ type VpnGatewayGenerator struct { AWSService } -func (VpnGatewayGenerator) createResources(vpnGws *ec2.DescribeVpnGatewaysResponse) []terraformutils.Resource { - resources := []terraformutils.Resource{} +func (VpnGatewayGenerator) createResources(vpnGws *ec2.DescribeVpnGatewaysOutput) []terraformutils.Resource { + var resources []terraformutils.Resource for _, vpnGw := range vpnGws.VpnGateways { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(vpnGw.VpnGatewayId), - aws.StringValue(vpnGw.VpnGatewayId), + StringValue(vpnGw.VpnGatewayId), + StringValue(vpnGw.VpnGatewayId), "aws_vpn_gateway", "aws", VpnAllowEmptyValues, @@ -51,8 +50,8 @@ func (g *VpnGatewayGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - vpnGws, err := svc.DescribeVpnGatewaysRequest(&ec2.DescribeVpnGatewaysInput{}).Send(context.Background()) + svc := ec2.NewFromConfig(config) + vpnGws, err := svc.DescribeVpnGateways(context.TODO(), &ec2.DescribeVpnGatewaysInput{}) if err != nil { return err } diff --git a/providers/aws/vpc.go b/providers/aws/vpc.go index b3a5f63f7..d37501349 100644 --- a/providers/aws/vpc.go +++ b/providers/aws/vpc.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -33,8 +32,8 @@ func (VpcGenerator) createResources(vpcs *ec2.DescribeVpcsOutput) []terraformuti var resources []terraformutils.Resource for _, vpc := range vpcs.Vpcs { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(vpc.VpcId), - aws.StringValue(vpc.VpcId), + StringValue(vpc.VpcId), + StringValue(vpc.VpcId), "aws_vpc", "aws", VpcAllowEmptyValues, @@ -51,10 +50,14 @@ func (g *VpcGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - p := ec2.NewDescribeVpcsPaginator(svc.DescribeVpcsRequest(&ec2.DescribeVpcsInput{})) - for p.Next(context.Background()) { - g.Resources = append(g.Resources, g.createResources(p.CurrentPage())...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeVpcsPaginator(svc, &ec2.DescribeVpcsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - return p.Err() + return nil } diff --git a/providers/aws/vpc_peering.go b/providers/aws/vpc_peering.go index d8272527c..c28104db6 100644 --- a/providers/aws/vpc_peering.go +++ b/providers/aws/vpc_peering.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -30,11 +29,11 @@ type VpcPeeringConnectionGenerator struct { } func (g *VpcPeeringConnectionGenerator) createResources(peerings *ec2.DescribeVpcPeeringConnectionsOutput) []terraformutils.Resource { - resources := []terraformutils.Resource{} + var resources []terraformutils.Resource for _, peering := range peerings.VpcPeeringConnections { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(peering.VpcPeeringConnectionId), - aws.StringValue(peering.VpcPeeringConnectionId), + StringValue(peering.VpcPeeringConnectionId), + StringValue(peering.VpcPeeringConnectionId), "aws_vpc_peering_connection", "aws", peeringAllowEmptyValues, @@ -51,10 +50,14 @@ func (g *VpcPeeringConnectionGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - p := ec2.NewDescribeVpcPeeringConnectionsPaginator(svc.DescribeVpcPeeringConnectionsRequest(&ec2.DescribeVpcPeeringConnectionsInput{})) - for p.Next(context.Background()) { - g.Resources = append(g.Resources, g.createResources(p.CurrentPage())...) + svc := ec2.NewFromConfig(config) + p := ec2.NewDescribeVpcPeeringConnectionsPaginator(svc, &ec2.DescribeVpcPeeringConnectionsInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(page)...) } - return p.Err() + return nil } diff --git a/providers/aws/vpn_connection.go b/providers/aws/vpn_connection.go index 750efafd2..d9f2e4163 100644 --- a/providers/aws/vpn_connection.go +++ b/providers/aws/vpn_connection.go @@ -19,7 +19,6 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ) @@ -29,12 +28,12 @@ type VpnConnectionGenerator struct { AWSService } -func (VpnConnectionGenerator) createResources(vpncs *ec2.DescribeVpnConnectionsResponse) []terraformutils.Resource { - resources := []terraformutils.Resource{} +func (VpnConnectionGenerator) createResources(vpncs *ec2.DescribeVpnConnectionsOutput) []terraformutils.Resource { + var resources []terraformutils.Resource for _, vpnc := range vpncs.VpnConnections { resources = append(resources, terraformutils.NewSimpleResource( - aws.StringValue(vpnc.ConnectionId), - aws.StringValue(vpnc.ConnectionId), + StringValue(vpnc.VpnConnectionId), + StringValue(vpnc.VpnConnectionId), "aws_vpn_connection", "aws", VpnConnectionAllowEmptyValues, @@ -51,8 +50,8 @@ func (g *VpnConnectionGenerator) InitResources() error { if e != nil { return e } - svc := ec2.New(config) - vpncs, err := svc.DescribeVpnConnectionsRequest(&ec2.DescribeVpnConnectionsInput{}).Send(context.Background()) + svc := ec2.NewFromConfig(config) + vpncs, err := svc.DescribeVpnConnections(context.TODO(), &ec2.DescribeVpnConnectionsInput{}) if err != nil { return err } diff --git a/providers/aws/waf.go b/providers/aws/waf.go index 6245ddaf6..a8c087bde 100644 --- a/providers/aws/waf.go +++ b/providers/aws/waf.go @@ -32,7 +32,7 @@ func (g *WafGenerator) InitResources() error { if e != nil { return e } - svc := waf.New(config) + svc := waf.NewFromConfig(config) if err := g.loadWebACL(svc); err != nil { return err @@ -75,7 +75,7 @@ func (g *WafGenerator) InitResources() error { } func (g *WafGenerator) loadWebACL(svc *waf.Client) error { - output, err := svc.ListWebACLsRequest(&waf.ListWebACLsInput{}).Send(context.Background()) + output, err := svc.ListWebACLs(context.TODO(), &waf.ListWebACLsInput{}) if err != nil { return err } @@ -91,7 +91,7 @@ func (g *WafGenerator) loadWebACL(svc *waf.Client) error { } func (g *WafGenerator) loadByteMatchSet(svc *waf.Client) error { - output, err := svc.ListByteMatchSetsRequest(&waf.ListByteMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListByteMatchSets(context.TODO(), &waf.ListByteMatchSetsInput{}) if err != nil { return err } @@ -107,7 +107,7 @@ func (g *WafGenerator) loadByteMatchSet(svc *waf.Client) error { } func (g *WafGenerator) loadGeoMatchSet(svc *waf.Client) error { - output, err := svc.ListGeoMatchSetsRequest(&waf.ListGeoMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListGeoMatchSets(context.TODO(), &waf.ListGeoMatchSetsInput{}) if err != nil { return err } @@ -123,7 +123,7 @@ func (g *WafGenerator) loadGeoMatchSet(svc *waf.Client) error { } func (g *WafGenerator) loadIPSet(svc *waf.Client) error { - output, err := svc.ListIPSetsRequest(&waf.ListIPSetsInput{}).Send(context.Background()) + output, err := svc.ListIPSets(context.TODO(), &waf.ListIPSetsInput{}) if err != nil { return err } @@ -139,7 +139,7 @@ func (g *WafGenerator) loadIPSet(svc *waf.Client) error { } func (g *WafGenerator) loadRateBasedRules(svc *waf.Client) error { - output, err := svc.ListRateBasedRulesRequest(&waf.ListRateBasedRulesInput{}).Send(context.Background()) + output, err := svc.ListRateBasedRules(context.TODO(), &waf.ListRateBasedRulesInput{}) if err != nil { return err } @@ -155,7 +155,7 @@ func (g *WafGenerator) loadRateBasedRules(svc *waf.Client) error { } func (g *WafGenerator) loadRegexMatchSets(svc *waf.Client) error { - output, err := svc.ListRegexMatchSetsRequest(&waf.ListRegexMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListRegexMatchSets(context.TODO(), &waf.ListRegexMatchSetsInput{}) if err != nil { return err } @@ -171,7 +171,7 @@ func (g *WafGenerator) loadRegexMatchSets(svc *waf.Client) error { } func (g *WafGenerator) loadRegexPatternSets(svc *waf.Client) error { - output, err := svc.ListRegexPatternSetsRequest(&waf.ListRegexPatternSetsInput{}).Send(context.Background()) + output, err := svc.ListRegexPatternSets(context.TODO(), &waf.ListRegexPatternSetsInput{}) if err != nil { return err } @@ -187,7 +187,7 @@ func (g *WafGenerator) loadRegexPatternSets(svc *waf.Client) error { } func (g *WafGenerator) loadWafRules(svc *waf.Client) error { - output, err := svc.ListRulesRequest(&waf.ListRulesInput{}).Send(context.Background()) + output, err := svc.ListRules(context.TODO(), &waf.ListRulesInput{}) if err != nil { return err } @@ -203,7 +203,7 @@ func (g *WafGenerator) loadWafRules(svc *waf.Client) error { } func (g *WafGenerator) loadWafRuleGroups(svc *waf.Client) error { - output, err := svc.ListRuleGroupsRequest(&waf.ListRuleGroupsInput{}).Send(context.Background()) + output, err := svc.ListRuleGroups(context.TODO(), &waf.ListRuleGroupsInput{}) if err != nil { return err } @@ -219,7 +219,7 @@ func (g *WafGenerator) loadWafRuleGroups(svc *waf.Client) error { } func (g *WafGenerator) loadSizeConstraintSets(svc *waf.Client) error { - output, err := svc.ListSizeConstraintSetsRequest(&waf.ListSizeConstraintSetsInput{}).Send(context.Background()) + output, err := svc.ListSizeConstraintSets(context.TODO(), &waf.ListSizeConstraintSetsInput{}) if err != nil { return err } @@ -235,7 +235,7 @@ func (g *WafGenerator) loadSizeConstraintSets(svc *waf.Client) error { } func (g *WafGenerator) loadSQLInjectionMatchSets(svc *waf.Client) error { - output, err := svc.ListSqlInjectionMatchSetsRequest(&waf.ListSqlInjectionMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListSqlInjectionMatchSets(context.TODO(), &waf.ListSqlInjectionMatchSetsInput{}) if err != nil { return err } @@ -251,7 +251,7 @@ func (g *WafGenerator) loadSQLInjectionMatchSets(svc *waf.Client) error { } func (g *WafGenerator) loadXSSMatchSet(svc *waf.Client) error { - output, err := svc.ListXssMatchSetsRequest(&waf.ListXssMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListXssMatchSets(context.TODO(), &waf.ListXssMatchSetsInput{}) if err != nil { return err } diff --git a/providers/aws/waf_regional.go b/providers/aws/waf_regional.go index ac39b01bd..abdcc1675 100644 --- a/providers/aws/waf_regional.go +++ b/providers/aws/waf_regional.go @@ -30,7 +30,7 @@ func (g *WafRegionalGenerator) InitResources() error { if e != nil { return e } - svc := wafregional.New(config) + svc := wafregional.NewFromConfig(config) if err := g.loadWebACL(svc); err != nil { return err @@ -74,7 +74,7 @@ func (g *WafRegionalGenerator) InitResources() error { } func (g *WafRegionalGenerator) loadWebACL(svc *wafregional.Client) error { - output, err := svc.ListWebACLsRequest(&wafregional.ListWebACLsInput{}).Send(context.Background()) + output, err := svc.ListWebACLs(context.TODO(), &wafregional.ListWebACLsInput{}) if err != nil { return err } @@ -90,7 +90,7 @@ func (g *WafRegionalGenerator) loadWebACL(svc *wafregional.Client) error { } func (g *WafRegionalGenerator) loadByteMatchSet(svc *wafregional.Client) error { - output, err := svc.ListByteMatchSetsRequest(&wafregional.ListByteMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListByteMatchSets(context.TODO(), &wafregional.ListByteMatchSetsInput{}) if err != nil { return err } @@ -106,7 +106,7 @@ func (g *WafRegionalGenerator) loadByteMatchSet(svc *wafregional.Client) error { } func (g *WafRegionalGenerator) loadGeoMatchSet(svc *wafregional.Client) error { - output, err := svc.ListGeoMatchSetsRequest(&wafregional.ListGeoMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListGeoMatchSets(context.TODO(), &wafregional.ListGeoMatchSetsInput{}) if err != nil { return err } @@ -122,7 +122,7 @@ func (g *WafRegionalGenerator) loadGeoMatchSet(svc *wafregional.Client) error { } func (g *WafRegionalGenerator) loadIPSet(svc *wafregional.Client) error { - output, err := svc.ListIPSetsRequest(&wafregional.ListIPSetsInput{}).Send(context.Background()) + output, err := svc.ListIPSets(context.TODO(), &wafregional.ListIPSetsInput{}) if err != nil { return err } @@ -138,7 +138,7 @@ func (g *WafRegionalGenerator) loadIPSet(svc *wafregional.Client) error { } func (g *WafRegionalGenerator) loadRateBasedRules(svc *wafregional.Client) error { - output, err := svc.ListRateBasedRulesRequest(&wafregional.ListRateBasedRulesInput{}).Send(context.Background()) + output, err := svc.ListRateBasedRules(context.TODO(), &wafregional.ListRateBasedRulesInput{}) if err != nil { return err } @@ -154,7 +154,7 @@ func (g *WafRegionalGenerator) loadRateBasedRules(svc *wafregional.Client) error } func (g *WafRegionalGenerator) loadRegexMatchSets(svc *wafregional.Client) error { - output, err := svc.ListRegexMatchSetsRequest(&wafregional.ListRegexMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListRegexMatchSets(context.TODO(), &wafregional.ListRegexMatchSetsInput{}) if err != nil { return err } @@ -170,7 +170,7 @@ func (g *WafRegionalGenerator) loadRegexMatchSets(svc *wafregional.Client) error } func (g *WafRegionalGenerator) loadRegexPatternSets(svc *wafregional.Client) error { - output, err := svc.ListRegexPatternSetsRequest(&wafregional.ListRegexPatternSetsInput{}).Send(context.Background()) + output, err := svc.ListRegexPatternSets(context.TODO(), &wafregional.ListRegexPatternSetsInput{}) if err != nil { return err } @@ -186,7 +186,7 @@ func (g *WafRegionalGenerator) loadRegexPatternSets(svc *wafregional.Client) err } func (g *WafRegionalGenerator) loadWafRules(svc *wafregional.Client) error { - output, err := svc.ListRulesRequest(&wafregional.ListRulesInput{}).Send(context.Background()) + output, err := svc.ListRules(context.TODO(), &wafregional.ListRulesInput{}) if err != nil { return err } @@ -202,7 +202,7 @@ func (g *WafRegionalGenerator) loadWafRules(svc *wafregional.Client) error { } func (g *WafRegionalGenerator) loadWafRuleGroups(svc *wafregional.Client) error { - output, err := svc.ListRuleGroupsRequest(&wafregional.ListRuleGroupsInput{}).Send(context.Background()) + output, err := svc.ListRuleGroups(context.TODO(), &wafregional.ListRuleGroupsInput{}) if err != nil { return err } @@ -218,7 +218,7 @@ func (g *WafRegionalGenerator) loadWafRuleGroups(svc *wafregional.Client) error } func (g *WafRegionalGenerator) loadSizeConstraintSets(svc *wafregional.Client) error { - output, err := svc.ListSizeConstraintSetsRequest(&wafregional.ListSizeConstraintSetsInput{}).Send(context.Background()) + output, err := svc.ListSizeConstraintSets(context.TODO(), &wafregional.ListSizeConstraintSetsInput{}) if err != nil { return err } @@ -234,7 +234,7 @@ func (g *WafRegionalGenerator) loadSizeConstraintSets(svc *wafregional.Client) e } func (g *WafRegionalGenerator) loadSQLInjectionMatchSets(svc *wafregional.Client) error { - output, err := svc.ListSqlInjectionMatchSetsRequest(&wafregional.ListSqlInjectionMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListSqlInjectionMatchSets(context.TODO(), &wafregional.ListSqlInjectionMatchSetsInput{}) if err != nil { return err } @@ -250,7 +250,7 @@ func (g *WafRegionalGenerator) loadSQLInjectionMatchSets(svc *wafregional.Client } func (g *WafRegionalGenerator) loadXSSMatchSet(svc *wafregional.Client) error { - output, err := svc.ListXssMatchSetsRequest(&wafregional.ListXssMatchSetsInput{}).Send(context.Background()) + output, err := svc.ListXssMatchSets(context.TODO(), &wafregional.ListXssMatchSetsInput{}) if err != nil { return err } diff --git a/providers/aws/workspaces.go b/providers/aws/workspaces.go index bd44f9d50..ed5412e26 100644 --- a/providers/aws/workspaces.go +++ b/providers/aws/workspaces.go @@ -18,7 +18,6 @@ import ( "context" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/workspaces" ) @@ -33,7 +32,7 @@ func (g *WorkspacesGenerator) InitResources() error { if e != nil { return e } - svc := workspaces.New(config) + svc := workspaces.NewFromConfig(config) if err := g.loadWorkspaces(svc); err != nil { return err } @@ -44,11 +43,15 @@ func (g *WorkspacesGenerator) InitResources() error { } func (g *WorkspacesGenerator) loadWorkspaces(svc *workspaces.Client) error { - p := workspaces.NewDescribeWorkspacesPaginator(svc.DescribeWorkspacesRequest(&workspaces.DescribeWorkspacesInput{})) - for p.Next(context.Background()) { - for _, workspace := range p.CurrentPage().Workspaces { - directoryID := aws.StringValue(workspace.DirectoryId) - workspaceID := aws.StringValue(workspace.WorkspaceId) + p := workspaces.NewDescribeWorkspacesPaginator(svc, &workspaces.DescribeWorkspacesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, workspace := range page.Workspaces { + directoryID := StringValue(workspace.DirectoryId) + workspaceID := StringValue(workspace.WorkspaceId) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( directoryID, directoryID, @@ -63,18 +66,18 @@ func (g *WorkspacesGenerator) loadWorkspaces(svc *workspaces.Client) error { workspacesAllowEmptyValues)) } } - return p.Err() + return nil } func (g *WorkspacesGenerator) loadWorkspacesIPGroup(svc *workspaces.Client) error { var nextToken *string for { - response, err := svc.DescribeIpGroupsRequest(&workspaces.DescribeIpGroupsInput{NextToken: nextToken}).Send(context.Background()) + response, err := svc.DescribeIpGroups(context.TODO(), &workspaces.DescribeIpGroupsInput{NextToken: nextToken}) if err != nil { return err } for _, ipGroup := range response.Result { - groupID := aws.StringValue(ipGroup.GroupId) + groupID := StringValue(ipGroup.GroupId) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( groupID, groupID, diff --git a/providers/aws/xray.go b/providers/aws/xray.go index a670f5a06..bc4a27893 100644 --- a/providers/aws/xray.go +++ b/providers/aws/xray.go @@ -18,11 +18,15 @@ func (g *XrayGenerator) InitResources() error { if e != nil { return e } - svc := xray.New(config) + svc := xray.NewFromConfig(config) - p := xray.NewGetSamplingRulesPaginator(svc.GetSamplingRulesRequest(&xray.GetSamplingRulesInput{})) - for p.Next(context.Background()) { - for _, samplingRule := range p.CurrentPage().SamplingRuleRecords { + p := xray.NewGetSamplingRulesPaginator(svc, &xray.GetSamplingRulesInput{}) + for p.HasMorePages() { + page, err := p.NextPage(context.TODO()) + if err != nil { + return err + } + for _, samplingRule := range page.SamplingRuleRecords { // NOTE: Builtin rule with unmodifiable name and 10000 prirority (lowest) if *samplingRule.SamplingRule.RuleName != "Default" { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( @@ -31,10 +35,6 @@ func (g *XrayGenerator) InitResources() error { "aws_xray_sampling_rule", "aws", xrayAllowEmptyValues)) - - if err := p.Err(); err != nil { - return err - } } } } diff --git a/providers/azure/analysis.go b/providers/azure/analysis.go index e69606b8c..f3b1eb951 100644 --- a/providers/azure/analysis.go +++ b/providers/azure/analysis.go @@ -35,7 +35,16 @@ func (g *AnalysisGenerator) listServiceServers() ([]terraformutils.Resource, err AnalysisClient := analysisservices.NewServersClient(g.Args["config"].(authentication.Config).SubscriptionID) AnalysisClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - servers, err := AnalysisClient.List(ctx) + var ( + servers analysisservices.Servers + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + servers, err = AnalysisClient.ListByResourceGroup(ctx, rg) + } else { + servers, err = AnalysisClient.List(ctx) + } if err != nil { return nil, err } diff --git a/providers/azure/app_service.go b/providers/azure/app_service.go index b3f7c993e..e63d14ddb 100644 --- a/providers/azure/app_service.go +++ b/providers/azure/app_service.go @@ -21,7 +21,15 @@ func (g AppServiceGenerator) listApps() ([]terraformutils.Resource, error) { appServiceClient := web.NewAppsClient(g.Args["config"].(authentication.Config).SubscriptionID) appServiceClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - appsIterator, err := appServiceClient.ListComplete(ctx) + var ( + appsIterator web.AppCollectionIterator + err error + ) + if rg := g.Args["resource_group"].(string); rg != "" { + appsIterator, err = appServiceClient.ListByResourceGroupComplete(ctx, rg, nil) + } else { + appsIterator, err = appServiceClient.ListComplete(ctx) + } if err != nil { return nil, err } diff --git a/providers/azure/application_gateway.go b/providers/azure/application_gateway.go new file mode 100644 index 000000000..7172146e5 --- /dev/null +++ b/providers/azure/application_gateway.go @@ -0,0 +1,70 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package azure + +import ( + "context" + "log" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" + "github.com/Azure/go-autorest/autorest" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/hashicorp/go-azure-helpers/authentication" +) + +type ApplicationGatewayGenerator struct { + AzureService +} + +func (g ApplicationGatewayGenerator) createResources(ctx context.Context, iterator network.ApplicationGatewayListResultIterator) ([]terraformutils.Resource, error) { + var resources []terraformutils.Resource + for iterator.NotDone() { + applicationGateways := iterator.Value() + resources = append(resources, terraformutils.NewSimpleResource( + *applicationGateways.ID, + *applicationGateways.Name, + "azurerm_application_gateway", + g.ProviderName, + []string{})) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + return resources, nil +} + +func (g *ApplicationGatewayGenerator) InitResources() error { + ctx := context.Background() + applicationGatewaysClient := network.NewApplicationGatewaysClient(g.Args["config"].(authentication.Config).SubscriptionID) + + applicationGatewaysClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) + + var ( + output network.ApplicationGatewayListResultIterator + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + output, err = applicationGatewaysClient.ListComplete(ctx, rg) + } else { + output, err = applicationGatewaysClient.ListAllComplete(ctx) + } + if err != nil { + return err + } + g.Resources, err = g.createResources(ctx, output) + return err +} diff --git a/providers/azure/azure_provider.go b/providers/azure/azure_provider.go index 45dd310a9..842a156af 100644 --- a/providers/azure/azure_provider.go +++ b/providers/azure/azure_provider.go @@ -21,16 +21,18 @@ import ( "strings" "github.com/Azure/go-autorest/autorest" - "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper" "github.com/hashicorp/go-azure-helpers/authentication" "github.com/hashicorp/go-azure-helpers/sender" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper" ) type AzureProvider struct { //nolint terraformutils.Provider - config authentication.Config - authorizer autorest.Authorizer + config authentication.Config + authorizer autorest.Authorizer + resourceGroup string } func (p *AzureProvider) setEnvConfig() error { @@ -105,6 +107,7 @@ func (p *AzureProvider) Init(args []string) error { return err } p.authorizer = authorizer + p.resourceGroup = args[0] return nil } @@ -146,14 +149,54 @@ func (AzureProvider) GetResourceConnections() map[string]map[string][]string { "app_service": { "resource_group": []string{"resource_group_name", "name"}, }, - "cosmosdb": { + "application_gateway": { "resource_group": []string{"resource_group_name", "name"}, }, + "cosmosdb": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + }, "container": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, }, "database": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + }, + "databricks": { + "resource_group": []string{ + "resource_group_name", "name", + "managed_resource_group_name", "name", + "location", "location", + }, + "storage_account": []string{"storage_account_name", "name"}, + "subnet": []string{ + "public_subnet_name", "name", + "private_subnet_name", "name", + }, + "virtual_network": []string{"virtual_network_id", "id"}, + }, + "data_factory": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "data_factory": []string{ + "data_factory_name", "name", + "data_factory_id", "id", + "linked_service_name", "name", + "integration_runtime_name", "name", + }, + "databricks": []string{"existing_cluster_id", "id"}, + "keyvault": []string{"keyvault_id", "id"}, + "storage_account": []string{"storage_account_id", "id"}, }, "disk": { "resource_group": []string{"resource_group_name", "name"}, @@ -161,32 +204,93 @@ func (AzureProvider) GetResourceConnections() map[string]map[string][]string { "dns": { "resource_group": []string{"resource_group_name", "name"}, }, - "keyvault": { + "eventhub": { "resource_group": []string{"resource_group_name", "name"}, + "eventhub": []string{ + "eventhub_name", "name", + "namespace_name", "name", + }, + }, + "keyvault": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, }, "load_balancer": { "resource_group": []string{"resource_group_name", "name"}, }, "network_interface": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "subnet": []string{"subnet_id", "id"}, }, "network_security_group": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "network_security_group": []string{"network_security_group_name", "name"}, + }, + "network_watcher": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "network_watcher": []string{"network_watcher_name", "name"}, + "storage_account": []string{"storage_account_id", "id"}, }, "private_dns": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{"resource_group_name", "name"}, + "virtual_network": []string{"virtual_network_id", "id"}, + "private_dns": []string{ + "zone_name", "name", + "private_dns_zone_name", "name", + }, + }, + "private_endpoint": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "subnet": []string{"subnet_id", "id"}, }, "public_ip": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + }, + "purview": { "resource_group": []string{"resource_group_name", "name"}, }, "redis": { "resource_group": []string{"resource_group_name", "name"}, }, + "route_table": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "route_table": []string{"route_table_name", "name"}, + }, "scaleset": { "resource_group": []string{"resource_group_name", "name"}, }, + "ssh_public_key": { + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + }, "storage_account": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "virtual_network": []string{"virtual_network_subnet_ids", "id"}, }, "storage_blob": { "storage_account": []string{"storage_account_name", "name"}, @@ -195,8 +299,26 @@ func (AzureProvider) GetResourceConnections() map[string]map[string][]string { "storage_container": { "storage_account": []string{"storage_account_name", "name"}, }, + "synapse": { + "resource_group": []string{ + "resource_group_name", "name", + "managed_resource_group_name", "name", + }, + "synapse": []string{"synapse_workspace_id", "id"}, + }, + "subnet": { + "resource_group": []string{"resource_group_name", "name"}, + "virtual_network": []string{"virtual_network_name", "name"}, + "network_security_group": []string{"network_security_group_id", "id"}, + "route_table": []string{"route_table_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, "virtual_machine": { - "resource_group": []string{"resource_group_name", "name"}, + "resource_group": []string{ + "resource_group_name", "name", + "location", "location", + }, + "network_interface": []string{"network_interface_ids", "id"}, }, "virtual_network": { "resource_group": []string{"resource_group_name", "name"}, @@ -208,25 +330,37 @@ func (p *AzureProvider) GetSupportedService() map[string]terraformutils.ServiceG return map[string]terraformutils.ServiceGenerator{ "analysis": &AnalysisGenerator{}, "app_service": &AppServiceGenerator{}, + "application_gateway": &ApplicationGatewayGenerator{}, "cosmosdb": &CosmosDBGenerator{}, "container": &ContainerGenerator{}, "database": &DatabasesGenerator{}, + "databricks": &DatabricksGenerator{}, + "data_factory": &DataFactoryGenerator{}, "disk": &DiskGenerator{}, "dns": &DNSGenerator{}, + "eventhub": &EventHubGenerator{}, "keyvault": &KeyVaultGenerator{}, "load_balancer": &LoadBalancerGenerator{}, + "management_lock": &ManagementLockGenerator{}, "network_interface": &NetworkInterfaceGenerator{}, "network_security_group": &NetworkSecurityGroupGenerator{}, + "network_watcher": &NetworkWatcherGenerator{}, "private_dns": &PrivateDNSGenerator{}, + "private_endpoint": &PrivateEndpointGenerator{}, "public_ip": &PublicIPGenerator{}, + "purview": &PurviewGenerator{}, "redis": &RedisGenerator{}, "resource_group": &ResourceGroupGenerator{}, + "route_table": &RouteTableGenerator{}, "scaleset": &ScaleSetGenerator{}, "security_center_contact": &SecurityCenterContactGenerator{}, "security_center_subscription_pricing": &SecurityCenterSubscriptionPricingGenerator{}, + "ssh_public_key": &SSHPublicKeyGenerator{}, "storage_account": &StorageAccountGenerator{}, "storage_blob": &StorageBlobGenerator{}, "storage_container": &StorageContainerGenerator{}, + "synapse": &SynapseGenerator{}, + "subnet": &SubnetGenerator{}, "virtual_machine": &VirtualMachineGenerator{}, "virtual_network": &VirtualNetworkGenerator{}, } @@ -242,8 +376,9 @@ func (p *AzureProvider) InitService(serviceName string, verbose bool) error { p.Service.SetVerbose(verbose) p.Service.SetProviderName(p.GetName()) p.Service.SetArgs(map[string]interface{}{ - "config": p.config, - "authorizer": p.authorizer, + "config": p.config, + "authorizer": p.authorizer, + "resource_group": p.resourceGroup, }) return nil } diff --git a/providers/azure/azure_service.go b/providers/azure/azure_service.go index 4f2975f1a..9cb9cddb2 100644 --- a/providers/azure/azure_service.go +++ b/providers/azure/azure_service.go @@ -15,9 +15,69 @@ package azure import ( + "github.com/Azure/go-autorest/autorest" "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/hashicorp/go-azure-helpers/authentication" + "strings" ) type AzureService struct { //nolint terraformutils.Service } + +func (az *AzureService) getClientArgs() (subscriptionID string, resourceGroup string, authorizer autorest.Authorizer) { + subs := az.Args["config"].(authentication.Config).SubscriptionID + auth := az.Args["authorizer"].(autorest.Authorizer) + resg := az.Args["resource_group"].(string) + return subs, resg, auth +} + +func (az *AzureService) AppendSimpleResource(id string, resourceName string, resourceType string) { + newResource := terraformutils.NewSimpleResource(id, resourceName, resourceType, az.ProviderName, []string{}) + az.Resources = append(az.Resources, newResource) +} + +func (az *AzureService) AppendSimpleResourceWithDuplicateCheck(id string, resourceName string, resourceType string) { + tferexist, _ := az.DuplicateCheck(id, resourceName, resourceType) + if !tferexist { + resourceName = resourceName + "_" + GenerateRandomString(6) + } + newResource := terraformutils.NewSimpleResource(id, resourceName, resourceType, az.ProviderName, []string{}) + az.Resources = append(az.Resources, newResource) +} + +// This method checks if same resource name(tfer) exists with +// same id +func (az *AzureService) DuplicateCheck(id string, resourceName string, resourceType string) (bool, bool) { + var tferexist, idexist bool + tferName := terraformutils.TfSanitize(resourceName) + for _, resource := range az.Resources { + if tferName == resource.ResourceName { + if id == resource.InstanceState.ID { + tferexist = true + idexist = true + } else { + tferexist = true + idexist = false + } + } + } + return tferexist, idexist +} + +func (az *AzureService) appendSimpleAssociation(id string, linkedResourceName string, resourceName *string, resourceType string, attributes map[string]string) { + var resourceName2 string + if resourceName != nil { + resourceName2 = *resourceName + } else { + resourceName0 := strings.ReplaceAll(resourceType, "azurerm_", "") + resourceName1 := resourceName0[strings.IndexByte(resourceName0, '_'):] + resourceName2 = linkedResourceName + resourceName1 + } + newResource := terraformutils.NewResource( + id, resourceName2, resourceType, az.ProviderName, attributes, + []string{"name"}, + map[string]interface{}{}, + ) + az.Resources = append(az.Resources, newResource) +} diff --git a/providers/azure/container.go b/providers/azure/container.go index 55879a4fe..fd9079226 100644 --- a/providers/azure/container.go +++ b/providers/azure/container.go @@ -36,7 +36,16 @@ func (g *ContainerGenerator) listAndAddForContainerGroup() ([]terraformutils.Res ContainerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID) ContainerGroupsClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - containerGroupIterator, err := ContainerGroupsClient.ListComplete(ctx) + var ( + containerGroupIterator containerinstance.ContainerGroupListResultIterator + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + containerGroupIterator, err = ContainerGroupsClient.ListByResourceGroupComplete(ctx, rg) + } else { + containerGroupIterator, err = ContainerGroupsClient.ListComplete(ctx) + } if err != nil { return nil, err } @@ -51,7 +60,7 @@ func (g *ContainerGenerator) listAndAddForContainerGroup() ([]terraformutils.Res if err := containerGroupIterator.Next(); err != nil { log.Println(err) - break + return resources, err } } @@ -93,7 +102,16 @@ func (g *ContainerGenerator) listAndAddForContainerRegistry() ([]terraformutils. ContainerRegistriesClient := containerregistry.NewRegistriesClient(subscriptionID) ContainerRegistriesClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - containerRegistryIterator, err := ContainerRegistriesClient.ListComplete(ctx) + var ( + containerRegistryIterator containerregistry.RegistryListResultIterator + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + containerRegistryIterator, err = ContainerRegistriesClient.ListByResourceGroupComplete(ctx, rg) + } else { + containerRegistryIterator, err = ContainerRegistriesClient.ListComplete(ctx) + } if err != nil { return nil, err } @@ -119,7 +137,7 @@ func (g *ContainerGenerator) listAndAddForContainerRegistry() ([]terraformutils. if err := containerRegistryIterator.Next(); err != nil { log.Println(err) - break + return resources, err } } diff --git a/providers/azure/cosmosdb.go b/providers/azure/cosmosdb.go index ead203718..1ae576b13 100644 --- a/providers/azure/cosmosdb.go +++ b/providers/azure/cosmosdb.go @@ -18,7 +18,7 @@ import ( "context" "strings" - "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2020-03-01/documentdb" + "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2021-06-15/documentdb" "github.com/Azure/go-autorest/autorest" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/hashicorp/go-azure-helpers/authentication" @@ -33,7 +33,7 @@ func (g *CosmosDBGenerator) listSQLDatabasesAndContainersBehind(resourceGroupNam var resourcesContainer []terraformutils.Resource ctx := context.Background() subscriptionID := g.Args["config"].(authentication.Config).SubscriptionID - SQLResourcesClient := documentdb.NewSQLResourcesClient(subscriptionID, subscriptionID) + SQLResourcesClient := documentdb.NewSQLResourcesClient(subscriptionID) SQLResourcesClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) sqlDatabases, err := SQLResourcesClient.ListSQLDatabases(ctx, resourceGroupName, accountName) @@ -81,11 +81,7 @@ func (g *CosmosDBGenerator) listTables(resourceGroupName string, accountName str var resources []terraformutils.Resource ctx := context.Background() subscriptionID := g.Args["config"].(authentication.Config).SubscriptionID - // NOTE: - // there will be a parameter simplification for interface if we update the package - // https://github.com/Azure/azure-sdk-for-go/blob/v42.0.0/services/cosmos-db/mgmt/2020-03-01/documentdb/tableresources.go#L35 - // https://github.com/Azure/azure-sdk-for-go/blob/v44.0.0/services/cosmos-db/mgmt/2020-03-01/documentdb/tableresources.go#L35 - TableResourcesClient := documentdb.NewTableResourcesClient(subscriptionID, subscriptionID) + TableResourcesClient := documentdb.NewTableResourcesClient(subscriptionID) TableResourcesClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) tables, err := TableResourcesClient.ListTables(ctx, resourceGroupName, accountName) @@ -108,14 +104,18 @@ func (g *CosmosDBGenerator) listAndAddForDatabaseAccounts() ([]terraformutils.Re var resources []terraformutils.Resource ctx := context.Background() subscriptionID := g.Args["config"].(authentication.Config).SubscriptionID - // NOTE: - // there will be a parameter simplification for interface if we update the package - // https://github.com/Azure/azure-sdk-for-go/blob/v42.0.0/services/cosmos-db/mgmt/2020-03-01/documentdb/databaseaccounts.go#L35 - // https://github.com/Azure/azure-sdk-for-go/blob/v44.0.0/services/cosmos-db/mgmt/2020-03-01/documentdb/databaseaccounts.go#L35 - DatabaseAccountsClient := documentdb.NewDatabaseAccountsClient(subscriptionID, subscriptionID) + DatabaseAccountsClient := documentdb.NewDatabaseAccountsClient(subscriptionID) DatabaseAccountsClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - accounts, err := DatabaseAccountsClient.List(ctx) + var ( + accounts documentdb.DatabaseAccountsListResult + err error + ) + if rg := g.Args["resource_group"].(string); rg != "" { + accounts, err = DatabaseAccountsClient.ListByResourceGroup(ctx, rg) + } else { + accounts, err = DatabaseAccountsClient.List(ctx) + } if err != nil { return nil, err } diff --git a/providers/azure/data_factory.go b/providers/azure/data_factory.go new file mode 100644 index 000000000..ce558f7f8 --- /dev/null +++ b/providers/azure/data_factory.go @@ -0,0 +1,388 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package azure + +import ( + "context" + "fmt" + "log" + "reflect" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/datafactory/mgmt/2018-06-01/datafactory" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type DataFactoryGenerator struct { + AzureService +} + +// Maps item.Properties.Type -> terraform.ResoruceType +// Information extracted from +// SupportedResources are in: +// @ github.com/azure/azure-sdk-for-go@v42.3.0+incompatible/services/datafactory/mgmt/2018-06-01/datafactory/models.go +// PossibleTypeBasicDatasetValues, PossibleTypeBasicIntegrationRuntimeValues, PossibleTypeBasicLinkedServiceValues, PossibleTypeBasicTriggerValues +// TypeBasicDataset,TypeBasicIntegrationRuntime, TypeBasicLinkedService, TypeBasicTrigger, TypeBasicDataFlow + +var ( + SupportedResources = map[string]string{ + "AzureBlob": "azurerm_data_factory_dataset_azure_blob", + "Binary": "azurerm_data_factory_dataset_binary", + "CosmosDbSqlApiCollection": "azurerm_data_factory_dataset_cosmosdb_sqlapi", + "CustomDataset": "azurerm_data_factory_custom_dataset", + "DelimitedText": "azurerm_data_factory_dataset_delimited_text", + "HttpFile": "azurerm_data_factory_dataset_http", + "Json": "azurerm_data_factory_dataset_json", + "MySqlTable": "azurerm_data_factory_dataset_mysql", + "Parquet": "azurerm_data_factory_dataset_parquet", + "PostgreSqlTable": "azurerm_data_factory_dataset_postgresql", + "SnowflakeTable": "azurerm_data_factory_dataset_snowflake", + "SqlServerTable": "azurerm_data_factory_dataset_sql_server_table", + "IntegrationRuntime": "azurerm_data_factory_integration_runtime_azure", + "Managed": "azurerm_data_factory_integration_runtime_azure_ssis", + "SelfHosted": "azurerm_data_factory_integration_runtime_self_hosted", + "AzureBlobStorage": "azurerm_data_factory_linked_service_azure_blob_storage", + "AzureDatabricks": "azurerm_data_factory_linked_service_azure_databricks", + "AzureFileStorage": "azurerm_data_factory_linked_service_azure_file_storage", + "AzureFunction": "azurerm_data_factory_linked_service_azure_function", + "AzureSearch": "azurerm_data_factory_linked_service_azure_search", + "AzureSqlDatabase": "azurerm_data_factory_linked_service_azure_sql_database", + "AzureTableStorage": "azurerm_data_factory_linked_service_azure_table_storage", + "CosmosDb": "azurerm_data_factory_linked_service_cosmosdb", + "CustomDataSource": "azurerm_data_factory_linked_custom_service", + "AzureBlobFS": "azurerm_data_factory_linked_service_data_lake_storage_gen2", + "AzureKeyVault": "azurerm_data_factory_linked_service_key_vault", + "AzureDataExplore": "azurerm_data_factory_linked_service_kusto", + "MySql": "azurerm_data_factory_linked_service_mysql", + "OData": "azurerm_data_factory_linked_service_odata", + "PostgreSql": "azurerm_data_factory_linked_service_postgresql", + "Sftp": "azurerm_data_factory_linked_service_sftp", + "Snowflake": "azurerm_data_factory_linked_service_snowflake", + "SqlServer": "azurerm_data_factory_linked_service_sql_server", + "AzureSqlDW": "azurerm_data_factory_linked_service_synapse", + "Web": "azurerm_data_factory_linked_service_web", + "BlobEventsTrigger": "azurerm_data_factory_trigger_blob_event", + "ScheduleTrigger": "azurerm_data_factory_trigger_schedule", + "TumblingWindowTrigger": "azurerm_data_factory_trigger_tumbling_window", + } +) + +func getResourceTypeFrom(azureResourceName string) string { + return SupportedResources[azureResourceName] +} + +func getFieldFrom(v interface{}, field string) reflect.Value { + reflected := reflect.ValueOf(v) + if reflected.IsValid() { + indirected := reflect.Indirect(reflected) + if indirected.Kind() == reflect.Struct { + fieldValue := indirected.FieldByName(field) + return fieldValue + } + } + return reflect.Value{} +} + +func getFieldAsString(v interface{}, field string) string { + fieldValue := getFieldFrom(v, field) + if fieldValue.IsValid() { + return fieldValue.String() + } + return "" +} + +func (az *AzureService) appendResourceAs(resources []terraformutils.Resource, itemID string, itemName string, resourceType string, abbreviation string) []terraformutils.Resource { + prefix := strings.ReplaceAll(resourceType, resourceType, abbreviation) + suffix := strings.ReplaceAll(itemName, "-", "_") + resourceName := prefix + "_" + suffix + res := terraformutils.NewSimpleResource(itemID, resourceName, resourceType, az.ProviderName, []string{}) + resources = append(resources, res) + return resources +} + +func (az *DataFactoryGenerator) appendResourceFrom(resources []terraformutils.Resource, id string, name string, properties interface{}) []terraformutils.Resource { + azureType := getFieldAsString(properties, "Type") + if azureType != "" { + resourceType := getResourceTypeFrom(azureType) + if resourceType == "" { + msg := fmt.Sprintf(`azurerm_data_factory: resource "%s" id: %s type: %s not handled yet by terraform or terraformer`, name, id, azureType) + log.Println(msg) + } else { + resources = az.appendResourceAs(resources, id, name, resourceType, "adf") + } + } + return resources +} + +func (az *DataFactoryGenerator) listFactories() ([]datafactory.Factory, error) { + subscriptionID, resourceGroup, authorizer := az.getClientArgs() + client := datafactory.NewFactoriesClient(subscriptionID) + client.Authorizer = authorizer + var ( + iterator datafactory.FactoryListResponseIterator + err error + ) + ctx := context.Background() + if resourceGroup != "" { + iterator, err = client.ListByResourceGroupComplete(ctx, resourceGroup) + } else { + iterator, err = client.ListComplete(ctx) + } + if err != nil { + return nil, err + } + var resources []datafactory.Factory + for iterator.NotDone() { + item := iterator.Value() + resources = append(resources, item) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createDataFactoryResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + var resources []terraformutils.Resource + for _, item := range dataFactories { + resources = az.appendResourceAs(resources, *item.ID, *item.Name, "azurerm_data_factory", "adf") + } + return resources, nil +} + +func getIntegrationRuntimeType(properties interface{}) string { + azureType := getFieldAsString(properties, "Type") + if azureType == "SelfHosted" { + return "azurerm_data_factory_integration_runtime_self_hosted" + } + // item.Properties.ManagedIntegrationRuntimeTypeProperties.SsisProperties + if typeProperties := getFieldFrom(properties, "ManagedIntegrationRuntimeTypeProperties"); typeProperties.IsValid() { + managedRuntime := typeProperties.Interface() + SsisProperties := getFieldFrom(managedRuntime, "SsisProperties") + if SsisProperties.IsNil() { + return "azurerm_data_factory_integration_runtime_azure" + } + } + return "azurerm_data_factory_integration_runtime_azure_ssis" +} + +func (az *DataFactoryGenerator) createIntegrationRuntimesResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewIntegrationRuntimesClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resourceType := getIntegrationRuntimeType(item.Properties) + resources = az.appendResourceAs(resources, *item.ID, *item.Name, resourceType, "adfr") + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createLinkedServiceResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewLinkedServicesClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resources = az.appendResourceFrom(resources, *item.ID, *item.Name, item.Properties) + if err = iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createPipelineResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewPipelinesClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resources = az.appendResourceAs(resources, *item.ID, *item.Name, "azurerm_data_factory_pipeline", "adfp") + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createPipelineTriggerScheduleResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewTriggersClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resources = az.appendResourceFrom(resources, *item.ID, *item.Name, item.Properties) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createDataFlowResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewDataFlowsClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resources = az.appendResourceAs(resources, *item.ID, *item.Name, "azurerm_data_factory_data_flow", "adfl") + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) createPipelineDatasetResources(dataFactories []datafactory.Factory) ([]terraformutils.Resource, error) { + subscriptionID, _, authorizer := az.getClientArgs() + client := datafactory.NewDatasetsClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + var resources []terraformutils.Resource + for _, factory := range dataFactories { + id, err := ParseAzureResourceID(*factory.ID) + if err != nil { + return nil, err + } + iterator, err := client.ListByFactoryComplete(ctx, id.ResourceGroup, *factory.Name) + if err != nil { + return nil, err + } + for iterator.NotDone() { + item := iterator.Value() + resources = az.appendResourceFrom(resources, *item.ID, *item.Name, item.Properties) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + } + return resources, nil +} + +func (az *DataFactoryGenerator) InitResources() error { + + dataFactories, err := az.listFactories() + if err != nil { + return err + } + + factoriesFunctions := []func([]datafactory.Factory) ([]terraformutils.Resource, error){ + az.createDataFactoryResources, + az.createIntegrationRuntimesResources, + az.createLinkedServiceResources, + az.createPipelineResources, + az.createPipelineTriggerScheduleResources, + az.createPipelineDatasetResources, + az.createDataFlowResources, + } + + for _, f := range factoriesFunctions { + resources, ero := f(dataFactories) + if ero != nil { + return ero + } + az.Resources = append(az.Resources, resources...) + } + return nil +} + +// PostGenerateHook for formatting json properties as heredoc +// - azurerm_data_factory_pipeline property activities_json +func (az *DataFactoryGenerator) PostConvertHook() error { + for i, resource := range az.Resources { + if resource.InstanceInfo.Type == "azurerm_data_factory_pipeline" { + if val, ok := az.Resources[i].Item["activities_json"]; ok { + if val != nil { + json := val.(string) + // json := asJson(val) + hereDoc := asHereDoc(json) + az.Resources[i].Item["activities_json"] = hereDoc + } + } + } + } + return nil +} diff --git a/providers/azure/database.go b/providers/azure/database.go index cd3018e94..bde48f162 100644 --- a/providers/azure/database.go +++ b/providers/azure/database.go @@ -40,7 +40,15 @@ func (g *DatabasesGenerator) getMariaDBServers() ([]mariadb.Server, error) { Client := mariadb.NewServersClient(SubscriptionID) Client.Authorizer = Authorizer - Servers, err := Client.List(ctx) + var ( + Servers mariadb.ServerListResult + err error + ) + if rg := g.Args["resource_group"].(string); rg != "" { + Servers, err = Client.ListByResourceGroup(ctx, rg) + } else { + Servers, err = Client.List(ctx) + } if err != nil { return nil, err } @@ -205,7 +213,16 @@ func (g *DatabasesGenerator) getMySQLServers() ([]mysql.Server, error) { Client := mysql.NewServersClient(SubscriptionID) Client.Authorizer = Authorizer - Servers, err := Client.List(ctx) + var ( + Servers mysql.ServerListResult + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + Servers, err = Client.ListByResourceGroup(ctx, rg) + } else { + Servers, err = Client.List(ctx) + } if err != nil { return nil, err } @@ -373,7 +390,17 @@ func (g *DatabasesGenerator) getPostgreSQLServers() ([]postgresql.Server, error) Client := postgresql.NewServersClient(SubscriptionID) Client.Authorizer = Authorizer - Servers, err := Client.List(ctx) + var ( + Servers postgresql.ServerListResult + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + Servers, err = Client.ListByResourceGroup(ctx, rg) + } else { + Servers, err = Client.List(ctx) + } + if err != nil { return nil, err } @@ -533,7 +560,16 @@ func (g *DatabasesGenerator) getSQLServers() ([]sql.Server, error) { Client := sql.NewServersClient(SubscriptionID) Client.Authorizer = Authorizer - ServerPages, err := Client.List(ctx) + var ( + ServerPages sql.ServerListResultPage + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + ServerPages, err = Client.ListByResourceGroup(ctx, rg) + } else { + ServerPages, err = Client.List(ctx) + } if err != nil { return nil, err } diff --git a/providers/azure/databricks.go b/providers/azure/databricks.go new file mode 100644 index 000000000..acede36ff --- /dev/null +++ b/providers/azure/databricks.go @@ -0,0 +1,71 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package azure + +import ( + "context" + "log" + + "github.com/Azure/azure-sdk-for-go/services/databricks/mgmt/2018-04-01/databricks" +) + +type DatabricksGenerator struct { + AzureService +} + +func (az *DatabricksGenerator) listWorkspaces() ([]databricks.Workspace, error) { + subscriptionID, resourceGroup, authorizer := az.getClientArgs() + client := databricks.NewWorkspacesClient(subscriptionID) + client.Authorizer = authorizer + var ( + iterator databricks.WorkspaceListResultIterator + err error + ) + ctx := context.Background() + if resourceGroup != "" { + iterator, err = client.ListByResourceGroupComplete(ctx, resourceGroup) + } else { + iterator, err = client.ListBySubscriptionComplete(ctx) + } + if err != nil { + return nil, err + } + var resources []databricks.Workspace + for iterator.NotDone() { + item := iterator.Value() + resources = append(resources, item) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + return resources, nil +} + +func (az *DatabricksGenerator) AppendWorkspace(workspace *databricks.Workspace) { + az.AppendSimpleResource(*workspace.ID, *workspace.Name, "azurerm_databricks_workspace") +} + +func (az *DatabricksGenerator) InitResources() error { + + workspaces, err := az.listWorkspaces() + if err != nil { + return err + } + for _, workspace := range workspaces { + az.AppendWorkspace(&workspace) + } + return nil +} diff --git a/providers/azure/disk.go b/providers/azure/disk.go index 64dd4c27d..bf727fb98 100644 --- a/providers/azure/disk.go +++ b/providers/azure/disk.go @@ -28,7 +28,7 @@ type DiskGenerator struct { AzureService } -func (g DiskGenerator) createResources(diskListIterator compute.DiskListIterator) []terraformutils.Resource { +func (g DiskGenerator) createResources(diskListIterator compute.DiskListIterator) ([]terraformutils.Resource, error) { var resources []terraformutils.Resource for diskListIterator.NotDone() { disk := diskListIterator.Value() @@ -40,10 +40,10 @@ func (g DiskGenerator) createResources(diskListIterator compute.DiskListIterator []string{})) if err := diskListIterator.Next(); err != nil { log.Println(err) - break + return resources, err } } - return resources + return resources, nil } func (g *DiskGenerator) InitResources() error { @@ -51,10 +51,20 @@ func (g *DiskGenerator) InitResources() error { disksClient := compute.NewDisksClient(g.Args["config"].(authentication.Config).SubscriptionID) disksClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) - output, err := disksClient.ListComplete(ctx) + + var ( + output compute.DiskListIterator + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + output, err = disksClient.ListByResourceGroupComplete(ctx, rg) + } else { + output, err = disksClient.ListComplete(ctx) + } if err != nil { return err } - g.Resources = g.createResources(output) - return nil + g.Resources, err = g.createResources(output) + return err } diff --git a/providers/azure/dns.go b/providers/azure/dns.go index 7795e29c0..dbe3db101 100644 --- a/providers/azure/dns.go +++ b/providers/azure/dns.go @@ -68,7 +68,7 @@ func (g *DNSGenerator) listRecordSets(resourceGroupName string, zoneName string, if err := recordSetIterator.Next(); err != nil { log.Println(err) - break + return resources, err } } @@ -83,7 +83,17 @@ func (g *DNSGenerator) listAndAddForDNSZone() ([]terraformutils.Resource, error) DNSZonesClient.Authorizer = g.Args["authorizer"].(autorest.Authorizer) var pageSize int32 = 50 - dnsZoneIterator, err := DNSZonesClient.ListComplete(ctx, &pageSize) + + var ( + dnsZoneIterator dns.ZoneListResultIterator + err error + ) + + if rg := g.Args["resource_group"].(string); rg != "" { + dnsZoneIterator, err = DNSZonesClient.ListByResourceGroupComplete(ctx, rg, &pageSize) + } else { + dnsZoneIterator, err = DNSZonesClient.ListComplete(ctx, &pageSize) + } if err != nil { return nil, err } @@ -109,7 +119,7 @@ func (g *DNSGenerator) listAndAddForDNSZone() ([]terraformutils.Resource, error) if err := dnsZoneIterator.Next(); err != nil { log.Println(err) - break + return resources, err } } diff --git a/providers/azure/eventhub.go b/providers/azure/eventhub.go new file mode 100644 index 000000000..6fd25bf9c --- /dev/null +++ b/providers/azure/eventhub.go @@ -0,0 +1,149 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package azure + +import ( + "context" + "log" + + "github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub" +) + +type EventHubGenerator struct { + AzureService +} + +func (az *EventHubGenerator) listNamespaces() ([]eventhub.EHNamespace, error) { + subscriptionID, resourceGroup, authorizer := az.getClientArgs() + client := eventhub.NewNamespacesClient(subscriptionID) + client.Authorizer = authorizer + var ( + iterator eventhub.EHNamespaceListResultIterator + err error + ) + ctx := context.Background() + if resourceGroup != "" { + iterator, err = client.ListByResourceGroupComplete(ctx, resourceGroup) + } else { + iterator, err = client.ListComplete(ctx) + } + if err != nil { + return nil, err + } + var resources []eventhub.EHNamespace + for iterator.NotDone() { + item := iterator.Value() + resources = append(resources, item) + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return resources, err + } + } + return resources, nil +} + +func (az *EventHubGenerator) AppendNamespace(namespace *eventhub.EHNamespace) { + az.AppendSimpleResource(*namespace.ID, *namespace.Name, "azurerm_eventhub_namespace") +} + +func (az *EventHubGenerator) appendEventHubs(namespace *eventhub.EHNamespace, namespaceRg *ResourceID) error { + subscriptionID, _, authorizer := az.getClientArgs() + client := eventhub.NewEventHubsClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + iterator, err := client.ListByNamespaceComplete(ctx, namespaceRg.ResourceGroup, *namespace.Name, nil, nil) + if err != nil { + return err + } + for iterator.NotDone() { + item := iterator.Value() + + az.AppendSimpleResource(*item.ID, *item.Name, "azurerm_eventhub") + err = az.appendConsumerGroups(namespace, namespaceRg, *item.Name) + if err != nil { + return err + } + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return err + } + } + return nil +} + +func (az *EventHubGenerator) appendConsumerGroups(namespace *eventhub.EHNamespace, namespaceRg *ResourceID, eventHubName string) error { + subscriptionID, _, authorizer := az.getClientArgs() + client := eventhub.NewConsumerGroupsClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + iterator, err := client.ListByEventHubComplete(ctx, namespaceRg.ResourceGroup, *namespace.Name, eventHubName, nil, nil) + if err != nil { + return err + } + for iterator.NotDone() { + item := iterator.Value() + az.AppendSimpleResource(*item.ID, *item.Name, "azurerm_eventhub_consumer_group") + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return err + } + } + return nil +} + +func (az *EventHubGenerator) appendAuthorizationRules(namespace *eventhub.EHNamespace, namespaceRg *ResourceID) error { + subscriptionID, _, authorizer := az.getClientArgs() + client := eventhub.NewNamespacesClient(subscriptionID) + client.Authorizer = authorizer + ctx := context.Background() + iterator, err := client.ListAuthorizationRulesComplete(ctx, namespaceRg.ResourceGroup, *namespace.Name) + if err != nil { + return err + } + for iterator.NotDone() { + item := iterator.Value() + + az.AppendSimpleResource(*item.ID, *item.Name, "azurerm_eventhub_namespace_authorization_rule") + if err := iterator.NextWithContext(ctx); err != nil { + log.Println(err) + return err + } + } + return nil +} + +func (az *EventHubGenerator) InitResources() error { + + namespaces, err := az.listNamespaces() + if err != nil { + return err + } + for _, namespace := range namespaces { + az.AppendNamespace(&namespace) + namespaceRg, err := ParseAzureResourceID(*namespace.ID) + if err != nil { + return err + } + err = az.appendEventHubs(&namespace, namespaceRg) + if err != nil { + return err + } + err = az.appendAuthorizationRules(&namespace, namespaceRg) + if err != nil { + return err + } + } + return nil +} diff --git a/providers/azure/helper.go b/providers/azure/helper.go index 3ba03db8d..14c05a8eb 100644 --- a/providers/azure/helper.go +++ b/providers/azure/helper.go @@ -16,6 +16,7 @@ package azure import ( "fmt" + "math/rand" "net/url" "strings" ) @@ -106,3 +107,18 @@ func ParseAzureResourceID(id string) (*ResourceID, error) { return idObj, nil } + +func GenerateRandomString(strlen int) string { + var lettersToUsed = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + RandomSlice := make([]rune, strlen) + for index := range RandomSlice { + RandomSlice[index] = lettersToUsed[rand.Intn(len(lettersToUsed))] + } + return string(RandomSlice) +} + +func asHereDoc(json string) string { + return fmt.Sprintf(`< 0 { + return val + } + } + } + return nil +} diff --git a/providers/azuredevops/project.go b/providers/azuredevops/project.go new file mode 100644 index 000000000..e0f4b7843 --- /dev/null +++ b/providers/azuredevops/project.go @@ -0,0 +1,51 @@ +package azuredevpos + +import ( + "context" + + "github.com/microsoft/azure-devops-go-api/azuredevops/core" +) + +type ProjectGenerator struct { + AzureDevOpsService +} + +func (az *ProjectGenerator) listResources() ([]core.TeamProjectReference, error) { + client, fail := az.getCoreClient() + if fail != nil { + return nil, fail + } + ctx := context.Background() + var resources []core.TeamProjectReference + pageArgs := core.GetProjectsArgs{} + pages, err := client.GetProjects(ctx, pageArgs) + for ; err == nil; pages, err = client.GetProjects(ctx, pageArgs) { + fetched := *pages + items := fetched.Value + resources = append(resources, items...) + if pages.ContinuationToken == "" { + return resources, nil + } + pageArgs = core.GetProjectsArgs{ + ContinuationToken: &pages.ContinuationToken, + } + } + return nil, err +} + +func (az *ProjectGenerator) appendResource(resource *core.TeamProjectReference) { + id := *resource.Id + az.appendSimpleResource(id.String(), *resource.Name, "azuredevops_project") +} + +func (az *ProjectGenerator) InitResources() error { + + resources, err := az.listResources() + if err != nil { + return err + } + for _, resource := range resources { + az.appendResource(&resource) + } + return nil +} diff --git a/providers/commercetools/api_extension.go b/providers/commercetools/api_extension.go index 92833c09f..520387744 100644 --- a/providers/commercetools/api_extension.go +++ b/providers/commercetools/api_extension.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *APIExtensionGenerator) InitResources() error { client := cfg.NewClient() - extensions, err := client.ExtensionQuery(&commercetools.QueryInput{}) + extensions, err := client.ExtensionQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/channel.go b/providers/commercetools/channel.go index d898fcb40..22d1d0e9b 100644 --- a/providers/commercetools/channel.go +++ b/providers/commercetools/channel.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *ChannelGenerator) InitResources() error { client := cfg.NewClient() - channels, err := client.ChannelQuery(&commercetools.QueryInput{}) + channels, err := client.ChannelQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/commercetools_provider.go b/providers/commercetools/commercetools_provider.go index f5a56d999..6dd6f7de1 100644 --- a/providers/commercetools/commercetools_provider.go +++ b/providers/commercetools/commercetools_provider.go @@ -77,6 +77,7 @@ func (p *CommercetoolsProvider) GetSupportedService() map[string]terraformutils. return map[string]terraformutils.ServiceGenerator{ "api_extension": &APIExtensionGenerator{}, "channel": &ChannelGenerator{}, + "custom_object": &CustomObjectGenerator{}, "product_type": &ProductTypeGenerator{}, "shipping_zone": &ShippingZoneGenerator{}, "shipping_method": &ShippingMethodGenerator{}, diff --git a/providers/commercetools/custom_object.go b/providers/commercetools/custom_object.go new file mode 100644 index 000000000..3860e5436 --- /dev/null +++ b/providers/commercetools/custom_object.go @@ -0,0 +1,57 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package commercetools + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/labd/commercetools-go-sdk/commercetools" +) + +type CustomObjectGenerator struct { + CommercetoolsService +} + +// InitResources generates Terraform Resources from Commercetools API +func (g *CustomObjectGenerator) InitResources() error { + cfg := connectivity.Config{ + ClientID: g.GetArgs()["client_id"].(string), + ClientSecret: g.GetArgs()["client_secret"].(string), + ClientScope: g.GetArgs()["client_scope"].(string), + TokenURL: g.GetArgs()["token_url"].(string) + "/oauth/token", + BaseURL: g.GetArgs()["base_url"].(string), + } + + client := cfg.NewClient() + + customObjects, err := client.CustomObjectQuery(context.Background(), &commercetools.QueryInput{}) + if err != nil { + return err + } + for _, customObject := range customObjects.Results { + g.Resources = append(g.Resources, terraformutils.NewResource( + customObject.ID, + customObject.Key, + "commercetools_custom_object", + "commercetools", + map[string]string{}, + []string{}, + map[string]interface{}{}, + )) + } + return nil +} diff --git a/providers/commercetools/product_type.go b/providers/commercetools/product_type.go index 8fa6eb9cb..c752174c9 100644 --- a/providers/commercetools/product_type.go +++ b/providers/commercetools/product_type.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *ProductTypeGenerator) InitResources() error { client := cfg.NewClient() - productTypes, err := client.ProductTypeQuery(&commercetools.QueryInput{}) + productTypes, err := client.ProductTypeQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/shipping_method.go b/providers/commercetools/shipping_method.go index 45d74e63c..2f99111a1 100644 --- a/providers/commercetools/shipping_method.go +++ b/providers/commercetools/shipping_method.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *ShippingMethodGenerator) InitResources() error { client := cfg.NewClient() - zones, err := client.ShippingMethodQuery(&commercetools.QueryInput{}) + zones, err := client.ShippingMethodQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/shipping_zone.go b/providers/commercetools/shipping_zone.go index 5d9214b7d..f6e8a8be8 100644 --- a/providers/commercetools/shipping_zone.go +++ b/providers/commercetools/shipping_zone.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *ShippingZoneGenerator) InitResources() error { client := cfg.NewClient() - zones, err := client.ZoneQuery(&commercetools.QueryInput{}) + zones, err := client.ZoneQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/state.go b/providers/commercetools/state.go index d987e327c..2a7ae8b72 100644 --- a/providers/commercetools/state.go +++ b/providers/commercetools/state.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *StateGenerator) InitResources() error { client := cfg.NewClient() - states, err := client.StateQuery(&commercetools.QueryInput{}) + states, err := client.StateQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/store.go b/providers/commercetools/store.go index 4a88233a5..ee432ae5a 100644 --- a/providers/commercetools/store.go +++ b/providers/commercetools/store.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *StoreGenerator) InitResources() error { client := cfg.NewClient() - stores, err := client.StoreQuery(&commercetools.QueryInput{}) + stores, err := client.StoreQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/subscription.go b/providers/commercetools/subscription.go index 0f2308cb4..092a60277 100644 --- a/providers/commercetools/subscription.go +++ b/providers/commercetools/subscription.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *SubscriptionGenerator) InitResources() error { client := cfg.NewClient() - subscriptions, err := client.SubscriptionQuery(&commercetools.QueryInput{}) + subscriptions, err := client.SubscriptionQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/tax_category.go b/providers/commercetools/tax_category.go index f99893371..1236b264c 100644 --- a/providers/commercetools/tax_category.go +++ b/providers/commercetools/tax_category.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *TaxCategoryGenerator) InitResources() error { client := cfg.NewClient() - categories, err := client.TaxCategoryQuery(&commercetools.QueryInput{}) + categories, err := client.TaxCategoryQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/commercetools/types.go b/providers/commercetools/types.go index f9db1e386..a379ff049 100644 --- a/providers/commercetools/types.go +++ b/providers/commercetools/types.go @@ -15,6 +15,8 @@ package commercetools import ( + "context" + "github.com/GoogleCloudPlatform/terraformer/providers/commercetools/connectivity" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/labd/commercetools-go-sdk/commercetools" @@ -36,7 +38,7 @@ func (g *TypesGenerator) InitResources() error { client := cfg.NewClient() - types, err := client.TypeQuery(&commercetools.QueryInput{}) + types, err := client.TypeQuery(context.Background(), &commercetools.QueryInput{}) if err != nil { return err } diff --git a/providers/datadog/dashboard.go b/providers/datadog/dashboard.go index 8559a56ae..1bbdfed6c 100644 --- a/providers/datadog/dashboard.go +++ b/providers/datadog/dashboard.go @@ -25,7 +25,7 @@ import ( var ( // DashboardAllowEmptyValues ... - DashboardAllowEmptyValues = []string{"tags."} + DashboardAllowEmptyValues = []string{"tags.", "manage_status_definition.*.query"} ) // DashboardGenerator ... @@ -33,7 +33,7 @@ type DashboardGenerator struct { DatadogService } -func (g *DashboardGenerator) createResources(dashboards []datadogV1.DashboardSummaryDashboards) []terraformutils.Resource { +func (g *DashboardGenerator) createResources(dashboards []datadogV1.DashboardSummaryDefinition) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, dashboard := range dashboards { resourceName := dashboard.GetId() @@ -64,7 +64,7 @@ func (g *DashboardGenerator) InitResources() error { for _, filter := range g.Filter { if filter.FieldPath == "id" && filter.IsApplicable("dashboard") { for _, value := range filter.AcceptableValues { - dashboard, _, err := datadogClientV1.DashboardsApi.GetDashboard(authV1, value).Execute() + dashboard, _, err := datadogClientV1.DashboardsApi.GetDashboard(authV1, value) if err != nil { return err } @@ -79,7 +79,7 @@ func (g *DashboardGenerator) InitResources() error { return nil } - summary, _, err := datadogClientV1.DashboardsApi.ListDashboards(authV1).Execute() + summary, _, err := datadogClientV1.DashboardsApi.ListDashboards(authV1) if err != nil { return err } diff --git a/providers/datadog/dashboard_json.go b/providers/datadog/dashboard_json.go new file mode 100644 index 000000000..e90fd51fb --- /dev/null +++ b/providers/datadog/dashboard_json.go @@ -0,0 +1,88 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // DashboardJSONAllowEmptyValues ... + DashboardJSONAllowEmptyValues = []string{"tags."} +) + +// DashboardJSONGenerator ... +type DashboardJSONGenerator struct { + DatadogService +} + +func (g *DashboardJSONGenerator) createResources(dashboards []datadogV1.DashboardSummaryDefinition) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, dashboard := range dashboards { + resourceName := dashboard.GetId() + resources = append(resources, g.createResource(resourceName)) + } + + return resources +} + +func (g *DashboardJSONGenerator) createResource(dashboardID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + dashboardID, + fmt.Sprintf("dashboard_json_%s", dashboardID), + "datadog_dashboard_json", + "datadog", + DashboardJSONAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each dashboard_json create 1 TerraformResource. +// Need Dashboard ID as ID for terraform resource +func (g *DashboardJSONGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("dashboard_json") { + for _, value := range filter.AcceptableValues { + dashboard, _, err := datadogClientV1.DashboardsApi.GetDashboard(authV1, value) + if err != nil { + return err + } + + resources = append(resources, g.createResource(dashboard.GetId())) + } + } + } + + if len(resources) > 0 { + g.Resources = resources + return nil + } + + summary, _, err := datadogClientV1.DashboardsApi.ListDashboards(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(summary.GetDashboards()) + return nil +} diff --git a/providers/datadog/dashboard_list.go b/providers/datadog/dashboard_list.go new file mode 100644 index 000000000..1cf06f03c --- /dev/null +++ b/providers/datadog/dashboard_list.go @@ -0,0 +1,70 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + "strconv" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // DashboardListAllowEmptyValues ... + DashboardListAllowEmptyValues = []string{} +) + +// DashboardListGenerator ... +type DashboardListGenerator struct { + DatadogService +} + +func (g *DashboardListGenerator) createResources(dashboardLists []datadogV1.DashboardList) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, dashboardList := range dashboardLists { + resourceID := strconv.FormatInt(dashboardList.GetId(), 10) + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *DashboardListGenerator) createResource(dashboardListID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + dashboardListID, + fmt.Sprintf("dashboard_list_%s", dashboardListID), + "datadog_dashboard_list", + "datadog", + DashboardListAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each dashboard_list create 1 TerraformResource. +// Need DashboardList ID as ID for terraform resource +func (g *DashboardListGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + dlResponse, _, err := datadogClientV1.DashboardListsApi.ListDashboardLists(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(dlResponse.GetDashboardLists()) + return nil +} diff --git a/providers/datadog/datadog_provider.go b/providers/datadog/datadog_provider.go index 2199e20bf..79a556f11 100644 --- a/providers/datadog/datadog_provider.go +++ b/providers/datadog/datadog_provider.go @@ -20,8 +20,10 @@ import ( "fmt" "net/url" "os" + "strconv" datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/zclconf/go-cty/cty" ) @@ -31,18 +33,38 @@ type DatadogProvider struct { //nolint apiKey string appKey string apiURL string + validate bool authV1 context.Context + authV2 context.Context datadogClientV1 *datadogV1.APIClient + datadogClientV2 *datadogV2.APIClient } // Init check env params and initialize API Client func (p *DatadogProvider) Init(args []string) error { + + if args[3] != "" { + validate, validateErr := strconv.ParseBool(args[3]) + if validateErr != nil { + return fmt.Errorf(`invalid validate arg : %v`, validateErr) + } + p.validate = validate + } else if os.Getenv("DATADOG_VALIDATE") != "" { + validate, validateErr := strconv.ParseBool(os.Getenv("DATADOG_VALIDATE")) + if validateErr != nil { + return fmt.Errorf(`invalid DATADOG_VALIDATE env var : %v`, validateErr) + } + p.validate = validate + } else { + p.validate = true + } + if args[0] != "" { p.apiKey = args[0] } else { if apiKey := os.Getenv("DATADOG_API_KEY"); apiKey != "" { p.apiKey = apiKey - } else { + } else if p.validate { return errors.New("api-key requirement") } } @@ -52,7 +74,7 @@ func (p *DatadogProvider) Init(args []string) error { } else { if appKey := os.Getenv("DATADOG_APP_KEY"); appKey != "" { p.appKey = appKey - } else { + } else if p.validate { return errors.New("app-key requirement") } } @@ -63,7 +85,7 @@ func (p *DatadogProvider) Init(args []string) error { p.apiURL = v } - // Initialize the Datadog API client + // Initialize the Datadog V1 API client authV1 := context.WithValue( context.Background(), datadogV1.ContextAPIKeys, @@ -91,11 +113,44 @@ func (p *DatadogProvider) Init(args []string) error { "protocol": parsedAPIURL.Scheme, }) } - p.authV1 = authV1 - configV1 := datadogV1.NewConfiguration() datadogClientV1 := datadogV1.NewAPIClient(configV1) + + // Initialize the Datadog V2 API client + authV2 := context.WithValue( + context.Background(), + datadogV2.ContextAPIKeys, + map[string]datadogV2.APIKey{ + "apiKeyAuth": { + Key: p.apiKey, + }, + "appKeyAuth": { + Key: p.appKey, + }, + }, + ) + if p.apiURL != "" { + parsedAPIURL, parseErr := url.Parse(p.apiURL) + if parseErr != nil { + return fmt.Errorf(`invalid API Url : %v`, parseErr) + } + if parsedAPIURL.Host == "" || parsedAPIURL.Scheme == "" { + return fmt.Errorf(`missing protocol or host : %v`, p.apiURL) + } + // If api url is passed, set and use the api name and protocol on ServerIndex{1} + authV2 = context.WithValue(authV2, datadogV2.ContextServerIndex, 1) + authV2 = context.WithValue(authV2, datadogV2.ContextServerVariables, map[string]string{ + "name": parsedAPIURL.Host, + "protocol": parsedAPIURL.Scheme, + }) + } + configV2 := datadogV2.NewConfiguration() + datadogClientV2 := datadogV2.NewAPIClient(configV2) + + p.authV1 = authV1 + p.authV2 = authV2 p.datadogClientV1 = datadogClientV1 + p.datadogClientV2 = datadogClientV2 return nil } @@ -108,9 +163,10 @@ func (p *DatadogProvider) GetName() string { // GetConfig return map of provider config for Datadog func (p *DatadogProvider) GetConfig() cty.Value { return cty.ObjectVal(map[string]cty.Value{ - "api_key": cty.StringVal(p.apiKey), - "app_key": cty.StringVal(p.appKey), - "api_url": cty.StringVal(p.apiURL), + "api_key": cty.StringVal(p.apiKey), + "app_key": cty.StringVal(p.appKey), + "api_url": cty.StringVal(p.apiURL), + "validate": cty.BoolVal(p.validate), }) } @@ -128,8 +184,11 @@ func (p *DatadogProvider) InitService(serviceName string, verbose bool) error { "api-key": p.apiKey, "app-key": p.appKey, "api-url": p.apiURL, + "validate": p.validate, "authV1": p.authV1, + "authV2": p.authV2, "datadogClientV1": p.datadogClientV1, + "datadogClientV2": p.datadogClientV2, }) return nil } @@ -137,19 +196,137 @@ func (p *DatadogProvider) InitService(serviceName string, verbose bool) error { // GetSupportedService return map of support service for Datadog func (p *DatadogProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { return map[string]terraformutils.ServiceGenerator{ - "dashboard": &DashboardGenerator{}, - "downtime": &DowntimeGenerator{}, - "monitor": &MonitorGenerator{}, - "screenboard": &ScreenboardGenerator{}, - "synthetics": &SyntheticsGenerator{}, - "timeboard": &TimeboardGenerator{}, - "user": &UserGenerator{}, + "dashboard_list": &DashboardListGenerator{}, + "dashboard": &DashboardGenerator{}, + "dashboard_json": &DashboardJSONGenerator{}, + "downtime": &DowntimeGenerator{}, + "logs_archive": &LogsArchiveGenerator{}, + "logs_archive_order": &LogsArchiveOrderGenerator{}, + "logs_custom_pipeline": &LogsCustomPipelineGenerator{}, + "logs_index": &LogsIndexGenerator{}, + "logs_index_order": &LogsIndexOrderGenerator{}, + "logs_integration_pipeline": &LogsIntegrationPipelineGenerator{}, + "logs_pipeline_order": &LogsPipelineOrderGenerator{}, + "integration_aws": &IntegrationAWSGenerator{}, + "integration_aws_lambda_arn": &IntegrationAWSLambdaARNGenerator{}, + "integration_aws_log_collection": &IntegrationAWSLogCollectionGenerator{}, + "integration_azure": &IntegrationAzureGenerator{}, + "integration_gcp": &IntegrationGCPGenerator{}, + "integration_pagerduty": &IntegrationPagerdutyGenerator{}, + "integration_pagerduty_service_object": &IntegrationPagerdutyServiceObjectGenerator{}, + "integration_slack_channel": &IntegrationSlackChannelGenerator{}, + "metric_metadata": &MetricMetadataGenerator{}, + "monitor": &MonitorGenerator{}, + "security_monitoring_default_rule": &SecurityMonitoringDefaultRuleGenerator{}, + "security_monitoring_rule": &SecurityMonitoringRuleGenerator{}, + "service_level_objective": &ServiceLevelObjectiveGenerator{}, + "synthetics_test": &SyntheticsTestGenerator{}, + "synthetics_global_variable": &SyntheticsGlobalVariableGenerator{}, + "synthetics_private_location": &SyntheticsPrivateLocationGenerator{}, + "user": &UserGenerator{}, + "role": &RoleGenerator{}, } } // GetResourceConnections return map of resource connections for Datadog -func (DatadogProvider) GetResourceConnections() map[string]map[string][]string { - return map[string]map[string][]string{} +func (p DatadogProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{ + "dashboard": { + "monitor": { + "widget.alert_graph_definition.alert_id", "id", + "widget.group_definition.widget.alert_graph_definition.alert_id", "id", + "widget.alert_value_definition.alert_id", "id", + "widget.group_definition.widget.alert_value_definition.alert_id", "id", + }, + "service_level_objective": { + "widget.service_level_objective_definition.slo_id", "id", + "widget.group_definition.widget.service_level_objective_definition.slo_id", "id", + }, + }, + "dashboard_list": { + "dashboard": { + "dash_item.dash_id", "id", + }, + }, + "downtime": { + "monitor": { + "monitor_id", "id", + }, + }, + "integration_aws_lambda_arn": { + "integration_aws": { + "account_id", "account_id", + }, + }, + "integration_aws_log_collection": { + "integration_aws": { + "account_id", "account_id", + }, + }, + "logs_archive": { + "integration_aws": { + "s3.account_id", "account_id", + "s3.role_name", "role_name", + "s3_archive.account_id", "account_id", + "s3_archive.role_name", "role_name", + }, + "integration_gcp": { + "gcs.project_id", "project_id", + "gcs.client_email", "client_email", + "gcs_archive.project_id", "project_id", + "gcs_archive.client_email", "client_email", + }, + "integration_azure": { + "azure.client_id", "client_id", + "azure.tenant_id", "tenant_name", + "azure_archive.client_id", "client_id", + "azure_archive.tenant_id", "tenant_name", + }, + }, + "logs_archive_order": { + "logs_archive": { + "archive_ids", "id", + }, + }, + "logs_index_order": { + "logs_index": { + "indexes", "id", + }, + }, + "logs_pipeline_order": { + "logs_integration_pipeline": { + "pipelines", "id", + }, + "logs_custom_pipeline": { + "pipelines", "id", + }, + }, + "monitor": { + "role": { + "restricted_roles", "id", + }, + }, + "service_level_objective": { + "monitor": { + "monitor_ids", "id", + }, + }, + "synthetics_test": { + "synthetics_private_location": { + "locations", "id", + }, + }, + "synthetics_global_variable": { + "synthetics_test": { + "parse_test_id", "id", + }, + }, + "user": { + "role": { + "roles", "id", + }, + }, + } } // GetProviderData return map of provider data for Datadog diff --git a/providers/datadog/downtime.go b/providers/datadog/downtime.go index 8e201c951..492194a5c 100644 --- a/providers/datadog/downtime.go +++ b/providers/datadog/downtime.go @@ -70,7 +70,7 @@ func (g *DowntimeGenerator) InitResources() error { return err } - monitor, _, err := datadogClientV1.DowntimesApi.GetDowntime(authV1, i).Execute() + monitor, _, err := datadogClientV1.DowntimesApi.GetDowntime(authV1, i) if err != nil { return err } @@ -85,7 +85,7 @@ func (g *DowntimeGenerator) InitResources() error { return nil } - downtimes, _, err := datadogClientV1.DowntimesApi.ListDowntimes(authV1).Execute() + downtimes, _, err := datadogClientV1.DowntimesApi.ListDowntimes(authV1) if err != nil { return err } diff --git a/providers/datadog/integration_aws.go b/providers/datadog/integration_aws.go new file mode 100644 index 000000000..ae4473fba --- /dev/null +++ b/providers/datadog/integration_aws.go @@ -0,0 +1,69 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationAWSAllowEmptyValues ... + IntegrationAWSAllowEmptyValues = []string{} +) + +// IntegrationAWSGenerator ... +type IntegrationAWSGenerator struct { + DatadogService +} + +func (g *IntegrationAWSGenerator) createResources(awsAccounts []datadogV1.AWSAccount) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, account := range awsAccounts { + resourceID := fmt.Sprintf("%s:%s", account.GetAccountId(), account.GetRoleName()) + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *IntegrationAWSGenerator) createResource(resourceID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + resourceID, + fmt.Sprintf("integration_aws_%s", resourceID), + "datadog_integration_aws", + "datadog", + IntegrationAWSAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each monitor create 1 TerraformResource. +// Need IntegrationAWS ID formatted as ':' as ID for terraform resource +func (g *IntegrationAWSGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + integrations, _, err := datadogClientV1.AWSIntegrationApi.ListAWSAccounts(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(integrations.GetAccounts()) + return nil +} diff --git a/providers/datadog/integration_aws_lambda_arn.go b/providers/datadog/integration_aws_lambda_arn.go new file mode 100644 index 000000000..a61163e65 --- /dev/null +++ b/providers/datadog/integration_aws_lambda_arn.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationAWSLambdaARNAllowEmptyValues ... + IntegrationAWSLambdaARNAllowEmptyValues = []string{} +) + +// IntegrationAWSLambdaARNGenerator ... +type IntegrationAWSLambdaARNGenerator struct { + DatadogService +} + +func (g *IntegrationAWSLambdaARNGenerator) createResources(logCollections []datadogV1.AWSLogsListResponse) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logCollection := range logCollections { + for _, logCollectionLambdaArn := range logCollection.GetLambdas() { + accountID := logCollection.GetAccountId() + if v, ok := logCollectionLambdaArn.GetArnOk(); ok { + resourceID := fmt.Sprintf("%s %s", accountID, *v) + resources = append(resources, g.createResource(resourceID)) + } + } + } + return resources +} + +func (g *IntegrationAWSLambdaARNGenerator) createResource(resourceID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + resourceID, + fmt.Sprintf("integration_aws_lambda_arn_%s", resourceID), + "datadog_integration_aws_lambda_arn", + "datadog", + IntegrationAWSLambdaARNAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each monitor create 1 TerraformResource. +// Need IntegrationAWSLambdaARN ID formatted as ':' as ID for terraform resource +func (g *IntegrationAWSLambdaARNGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + logCollections, _, err := datadogClientV1.AWSLogsIntegrationApi.ListAWSLogsIntegrations(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(logCollections) + return nil +} diff --git a/providers/datadog/integration_aws_log_collection.go b/providers/datadog/integration_aws_log_collection.go new file mode 100644 index 000000000..83db0ef0c --- /dev/null +++ b/providers/datadog/integration_aws_log_collection.go @@ -0,0 +1,78 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationAWSLogCollectionAllowEmptyValues ... + IntegrationAWSLogCollectionAllowEmptyValues = []string{"services"} +) + +// IntegrationAWSLogCollectionGenerator ... +type IntegrationAWSLogCollectionGenerator struct { + DatadogService +} + +func (g *IntegrationAWSLogCollectionGenerator) createResources(logCollections []datadogV1.AWSLogsListResponse) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logCollection := range logCollections { + resourceID := logCollection.GetAccountId() + resources = append(resources, g.createResource(resourceID)) + } + return resources +} + +func (g *IntegrationAWSLogCollectionGenerator) createResource(resourceID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + resourceID, + fmt.Sprintf("integration_aws_log_collection_%s", resourceID), + "datadog_integration_aws_log_collection", + "datadog", + IntegrationAWSLogCollectionAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each monitor create 1 TerraformResource. +// Need IntegrationAWSLogCollection ID formatted as ':' as ID for terraform resource +func (g *IntegrationAWSLogCollectionGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + logCollections, _, err := datadogClientV1.AWSLogsIntegrationApi.ListAWSLogsIntegrations(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(logCollections) + return nil +} + +func (g *IntegrationAWSLogCollectionGenerator) PostConvertHook() error { + for _, r := range g.Resources { + // services is a required attribute but can be empty. This ensures we append an empty list + if r.Item["services"] == nil { + r.Item["services"] = []string{} + } + } + return nil +} diff --git a/providers/datadog/integration_azure.go b/providers/datadog/integration_azure.go new file mode 100644 index 000000000..e4c576381 --- /dev/null +++ b/providers/datadog/integration_azure.go @@ -0,0 +1,69 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationAzureAllowEmptyValues ... + IntegrationAzureAllowEmptyValues = []string{} +) + +// IntegrationAzureGenerator ... +type IntegrationAzureGenerator struct { + DatadogService +} + +func (g *IntegrationAzureGenerator) createResources(azureAccounts []datadogV1.AzureAccount) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, account := range azureAccounts { + resourceID := fmt.Sprintf("%s:%s", account.GetTenantName(), account.GetClientId()) + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *IntegrationAzureGenerator) createResource(resourceID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + resourceID, + fmt.Sprintf("integration_azure_%s", resourceID), + "datadog_integration_azure", + "datadog", + IntegrationAzureAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each monitor create 1 TerraformResource. +// Need IntegrationAzure ID formatted as ':' as ID for terraform resource +func (g *IntegrationAzureGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + integrations, _, err := datadogClientV1.AzureIntegrationApi.ListAzureIntegration(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(integrations) + return nil +} diff --git a/providers/datadog/integration_gcp.go b/providers/datadog/integration_gcp.go new file mode 100644 index 000000000..412fdd5ea --- /dev/null +++ b/providers/datadog/integration_gcp.go @@ -0,0 +1,69 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationGCPAllowEmptyValues ... + IntegrationGCPAllowEmptyValues = []string{} +) + +// IntegrationGCPGenerator ... +type IntegrationGCPGenerator struct { + DatadogService +} + +func (g *IntegrationGCPGenerator) createResources(gcpAccounts []datadogV1.GCPAccount) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, account := range gcpAccounts { + resourceID := account.GetProjectId() + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *IntegrationGCPGenerator) createResource(resourceID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + resourceID, + fmt.Sprintf("integration_gcp_%s", resourceID), + "datadog_integration_gcp", + "datadog", + IntegrationGCPAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each monitor create 1 TerraformResource. +// Need IntegrationGCP ID formatted as ':' as ID for terraform resource +func (g *IntegrationGCPGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + integrations, _, err := datadogClientV1.GCPIntegrationApi.ListGCPIntegration(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(integrations) + return nil +} diff --git a/providers/datadog/integration_pagerduty.go b/providers/datadog/integration_pagerduty.go new file mode 100644 index 000000000..7b2b91d32 --- /dev/null +++ b/providers/datadog/integration_pagerduty.go @@ -0,0 +1,72 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "fmt" + + datadogCommunity "github.com/zorkian/go-datadog-api" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationPagerdutyAllowEmptyValues ... + IntegrationPagerdutyAllowEmptyValues = []string{"tags."} +) + +// IntegrationPagerdutyGenerator ... +type IntegrationPagerdutyGenerator struct { + DatadogService +} + +func (g *IntegrationPagerdutyGenerator) createResources(pdSubdomain string) []terraformutils.Resource { + resources := []terraformutils.Resource{} + resources = append(resources, g.createResource(pdSubdomain)) + + return resources +} + +func (g *IntegrationPagerdutyGenerator) createResource(serviceName string) terraformutils.Resource { + resource := terraformutils.NewResource( + serviceName, + fmt.Sprintf("integration_pagerduty_%s", serviceName), + "datadog_integration_pagerduty", + "datadog", + map[string]string{ + "individual_services": "true", + }, + IntegrationPagerdutyAllowEmptyValues, + map[string]interface{}{}, + ) + // Ignore services in favor of individual_services + resource.IgnoreKeys = append(resource.IgnoreKeys, "^services$") + + return resource +} + +// InitResources Generate TerraformResources from Datadog API, +// from PD Service create 1 TerraformResource. +// Need IntegrationPagerduty Subdomain as ID for terraform resource +func (g *IntegrationPagerdutyGenerator) InitResources() error { + client := datadogCommunity.NewClient(g.Args["api-key"].(string), g.Args["app-key"].(string)) + + integration, err := client.GetIntegrationPD() + if err != nil { + return err + } + g.Resources = g.createResources(integration.GetSubdomain()) + return nil +} diff --git a/providers/datadog/integration_pagerduty_service_object.go b/providers/datadog/integration_pagerduty_service_object.go new file mode 100644 index 000000000..103f12fc0 --- /dev/null +++ b/providers/datadog/integration_pagerduty_service_object.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "fmt" + + datadogCommunity "github.com/zorkian/go-datadog-api" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationPagerdutyServiceObjectAllowEmptyValues ... + IntegrationPagerdutyServiceObjectAllowEmptyValues = []string{"tags."} +) + +// IntegrationPagerdutyServiceObjectGenerator ... +type IntegrationPagerdutyServiceObjectGenerator struct { + DatadogService +} + +func (g *IntegrationPagerdutyServiceObjectGenerator) createResources(serviceNames []string) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, name := range serviceNames { + resourceName := name + resources = append(resources, g.createResource(resourceName)) + } + + return resources +} + +func (g *IntegrationPagerdutyServiceObjectGenerator) createResource(serviceName string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + serviceName, + fmt.Sprintf("integration_pagerduty_service_object_%s", serviceName), + "datadog_integration_pagerduty_service_object", + "datadog", + IntegrationPagerdutyServiceObjectAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each PD Service create 1 TerraformResource. +// Need IntegrationPagerdutyServiceObject ServiceName as ID for terraform resource +func (g *IntegrationPagerdutyServiceObjectGenerator) InitResources() error { + client := datadogCommunity.NewClient(g.Args["api-key"].(string), g.Args["app-key"].(string)) + + pdIntegration, err := client.GetIntegrationPD() + if err != nil { + return err + } + + var serviceNames []string + for _, service := range pdIntegration.Services { + serviceNames = append(serviceNames, *service.ServiceName) + } + + g.Resources = g.createResources(serviceNames) + return nil +} diff --git a/providers/datadog/integration_slack_channel.go b/providers/datadog/integration_slack_channel.go new file mode 100644 index 000000000..e122ef829 --- /dev/null +++ b/providers/datadog/integration_slack_channel.go @@ -0,0 +1,88 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + "log" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // IntegrationSlackChannelAllowEmptyValues ... + IntegrationSlackChannelAllowEmptyValues = []string{} +) + +// IntegrationSlackChannelGenerator ... +type IntegrationSlackChannelGenerator struct { + DatadogService +} + +func (g *IntegrationSlackChannelGenerator) createResources(accountID string, slackChannels []datadogV1.SlackIntegrationChannel) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, slackChannel := range slackChannels { + id := fmt.Sprintf("%s:%s", accountID, slackChannel.GetName()) + resources = append(resources, g.createResource(id)) + } + + return resources +} + +func (g *IntegrationSlackChannelGenerator) createResource(id string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + id, + fmt.Sprintf("integration_slack_channel_%s", id), + "datadog_integration_slack_channel", + "datadog", + IntegrationSlackChannelAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each slack channel create 1 TerraformResource. +func (g *IntegrationSlackChannelGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "account_name" && filter.IsApplicable("integration_slack_channel") { + for _, value := range filter.AcceptableValues { + slackChannels, _, err := datadogClientV1.SlackIntegrationApi.GetSlackIntegrationChannels(authV1, value) + if err != nil { + return err + } + + resources = g.createResources(value, slackChannels) + } + } + if filter.FieldPath == "id" && filter.IsApplicable("integration_slack_channel") { + for _, value := range filter.AcceptableValues { + resources = append(resources, g.createResource(value)) + } + } + } + + if len(resources) == 0 { + log.Print("Filter(account_name or resource id) is required to import datadog_integration_slack_channel resource") + return nil + } + g.Resources = resources + return nil +} diff --git a/providers/datadog/logs_archive.go b/providers/datadog/logs_archive.go new file mode 100644 index 000000000..05a48e08a --- /dev/null +++ b/providers/datadog/logs_archive.go @@ -0,0 +1,89 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsArchiveAllowEmptyValues ... + LogsArchiveAllowEmptyValues = []string{"path", "query"} +) + +// LogsArchiveGenerator ... +type LogsArchiveGenerator struct { + DatadogService +} + +func (g *LogsArchiveGenerator) createResources(logsArchives []datadogV2.LogsArchiveDefinition) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logsArchive := range logsArchives { + logsArchiveID := logsArchive.GetId() + resources = append(resources, g.createResource(logsArchiveID)) + } + + return resources +} + +func (g *LogsArchiveGenerator) createResource(logsArchiveID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + logsArchiveID, + fmt.Sprintf("logs_archive_%s", logsArchiveID), + "datadog_logs_archive", + "datadog", + LogsArchiveAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each archive create 1 TerraformResource. +// Need LogsArchive ID as ID for terraform resource +func (g *LogsArchiveGenerator) InitResources() error { + datadogClientV2 := g.Args["datadogClientV2"].(*datadogV2.APIClient) + authV2 := g.Args["authV2"].(context.Context) + + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("logs_archive") { + for _, value := range filter.AcceptableValues { + resp, _, err := datadogClientV2.LogsArchivesApi.GetLogsArchive(authV2, value) + if err != nil { + return err + } + logsArchiveData := resp.GetData() + resources = append(resources, g.createResource(logsArchiveData.GetId())) + } + } + } + + if len(resources) > 0 { + g.Resources = resources + return nil + } + + logsArchiveListResp, _, err := datadogClientV2.LogsArchivesApi.ListLogsArchives(authV2) + logsArchiveList := logsArchiveListResp.GetData() + if err != nil { + return err + } + g.Resources = g.createResources(logsArchiveList) + return nil +} diff --git a/providers/datadog/logs_archive_order.go b/providers/datadog/logs_archive_order.go new file mode 100644 index 000000000..baafed400 --- /dev/null +++ b/providers/datadog/logs_archive_order.go @@ -0,0 +1,43 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsArchiveOrderAllowEmptyValues ... + LogsArchiveOrderAllowEmptyValues = []string{} +) + +// LogsArchiveOrderGenerator ... +type LogsArchiveOrderGenerator struct { + DatadogService +} + +// InitResources Generate TerraformResources +func (g *LogsArchiveOrderGenerator) InitResources() error { + g.Resources = append(g.Resources, terraformutils.NewResource( + "archiveOrderID", + "archiveOrderID", + "datadog_logs_archive_order", + "datadog", + map[string]string{}, + LogsArchiveOrderAllowEmptyValues, + map[string]interface{}{}, + )) + return nil +} diff --git a/providers/datadog/logs_custom_pipeline.go b/providers/datadog/logs_custom_pipeline.go new file mode 100644 index 000000000..1ba0aa961 --- /dev/null +++ b/providers/datadog/logs_custom_pipeline.go @@ -0,0 +1,114 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsCustomPipelineAllowEmptyValues ... + LogsCustomPipelineAllowEmptyValues = []string{"support_rules", "filter"} +) + +// LogsCustomPipelineGenerator ... +type LogsCustomPipelineGenerator struct { + DatadogService +} + +func (g *LogsCustomPipelineGenerator) createResources(logsCustomPipelines []datadogV1.LogsPipeline) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logsCustomPipeline := range logsCustomPipelines { + // Import logs custom pipelines only + if !logsCustomPipeline.GetIsReadOnly() { + resourceName := logsCustomPipeline.GetId() + resources = append(resources, g.createResource(resourceName)) + } + } + + return resources +} + +func (g *LogsCustomPipelineGenerator) createResource(logsCustomPipelineID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + logsCustomPipelineID, + fmt.Sprintf("logs_custom_pipeline_%s", logsCustomPipelineID), + "datadog_logs_custom_pipeline", + "datadog", + LogsCustomPipelineAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each custom pipeline create 1 TerraformResource. +// Need LogsPipeline ID as ID for terraform resource +func (g *LogsCustomPipelineGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("logs_custom_pipeline") { + for _, value := range filter.AcceptableValues { + logsCustomPipeline, _, err := datadogClientV1.LogsPipelinesApi.GetLogsPipeline(authV1, value) + if err != nil { + return err + } + + resources = append(resources, g.createResource(logsCustomPipeline.GetId())) + } + } + } + + if len(resources) > 0 { + g.Resources = resources + return nil + } + + logsCustomPipelines, _, err := datadogClientV1.LogsPipelinesApi.ListLogsPipelines(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(logsCustomPipelines) + return nil +} + +func (g *LogsCustomPipelineGenerator) PostConvertHook() error { + for i, r := range g.Resources { + for k, v := range r.Item { + // Hack to properly escape `%{` used in pipeline processors + if k == "processor" { + var z interface{} + jsonByte, err := json.Marshal(v) + if err != nil { + continue + } + jsonByte = []byte(strings.ReplaceAll(string(jsonByte), "%{", "%%{")) + if err = json.Unmarshal(jsonByte, &z); err != nil { + continue + } + g.Resources[i].Item[k] = z + } + } + } + return nil +} diff --git a/providers/datadog/logs_index.go b/providers/datadog/logs_index.go new file mode 100644 index 000000000..73adeeb38 --- /dev/null +++ b/providers/datadog/logs_index.go @@ -0,0 +1,89 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsIndexAllowEmptyValues ... + LogsIndexAllowEmptyValues = []string{"filter"} +) + +// LogsIndexGenerator ... +type LogsIndexGenerator struct { + DatadogService +} + +func (g *LogsIndexGenerator) createResources(logsIndexes []datadogV1.LogsIndex) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logsIndex := range logsIndexes { + resourceName := logsIndex.GetName() + resources = append(resources, g.createResource(resourceName)) + } + + return resources +} + +func (g *LogsIndexGenerator) createResource(logsIndexName string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + logsIndexName, + fmt.Sprintf("logs_index_%s", logsIndexName), + "datadog_logs_index", + "datadog", + LogsIndexAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each index create 1 TerraformResource. +// Need LogsIndex Name as ID for terraform resource +func (g *LogsIndexGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("logs_index") { + for _, value := range filter.AcceptableValues { + logsIndex, _, err := datadogClientV1.LogsIndexesApi.GetLogsIndex(authV1, value) + if err != nil { + return err + } + + resources = append(resources, g.createResource(logsIndex.GetName())) + } + } + } + + if len(resources) > 0 { + g.Resources = resources + return nil + } + + logsIndexList, _, err := datadogClientV1.LogsIndexesApi.ListLogIndexes(authV1) + logsIndex := logsIndexList.GetIndexes() + if err != nil { + return err + } + g.Resources = g.createResources(logsIndex) + return nil +} diff --git a/providers/datadog/logs_index_order.go b/providers/datadog/logs_index_order.go new file mode 100644 index 000000000..2d2094314 --- /dev/null +++ b/providers/datadog/logs_index_order.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "fmt" + "time" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsIndexOrderAllowEmptyValues ... + LogsIndexOrderAllowEmptyValues = []string{} +) + +// LogsIndexOrderGenerator ... +type LogsIndexOrderGenerator struct { + DatadogService +} + +// InitResources Generate TerraformResources +func (g *LogsIndexOrderGenerator) InitResources() error { + currentDate := time.Now().Format("20060102150405") + resourceName := fmt.Sprintf("logs_index_order_%s", currentDate) + g.Resources = append(g.Resources, terraformutils.NewResource( + resourceName, + resourceName, + "datadog_logs_index_order", + "datadog", + map[string]string{ + "name": resourceName, + }, + LogsIndexOrderAllowEmptyValues, + map[string]interface{}{}, + )) + return nil +} diff --git a/providers/datadog/logs_integration_pipeline.go b/providers/datadog/logs_integration_pipeline.go new file mode 100644 index 000000000..6e8d57acb --- /dev/null +++ b/providers/datadog/logs_integration_pipeline.go @@ -0,0 +1,71 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsIntegrationPipelineAllowEmptyValues ... + LogsIntegrationPipelineAllowEmptyValues = []string{} +) + +// LogsIntegrationPipelineGenerator ... +type LogsIntegrationPipelineGenerator struct { + DatadogService +} + +func (g *LogsIntegrationPipelineGenerator) createResources(logsIntegrationPipelines []datadogV1.LogsPipeline) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, logsIntegrationPipeline := range logsIntegrationPipelines { + // Import logs integration pipelines only + if logsIntegrationPipeline.GetIsReadOnly() { + resourceID := logsIntegrationPipeline.GetId() + resourceName := logsIntegrationPipeline.GetName() + resources = append(resources, g.createResource(resourceID, resourceName)) + } + } + + return resources +} + +func (g *LogsIntegrationPipelineGenerator) createResource(logsIntegrationPipelineID string, logsIntegrationPipelineName string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + logsIntegrationPipelineID, + logsIntegrationPipelineName, + "datadog_logs_integration_pipeline", + "datadog", + LogsIntegrationPipelineAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each integration pipeline create 1 TerraformResource. +// Need LogsPipeline ID as ID for terraform resource +func (g *LogsIntegrationPipelineGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + logsIntegrationPipelines, _, err := datadogClientV1.LogsPipelinesApi.ListLogsPipelines(authV1) + if err != nil { + return err + } + g.Resources = g.createResources(logsIntegrationPipelines) + return nil +} diff --git a/providers/datadog/logs_pipeline_order.go b/providers/datadog/logs_pipeline_order.go new file mode 100644 index 000000000..a71b44124 --- /dev/null +++ b/providers/datadog/logs_pipeline_order.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "fmt" + "time" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // LogsPipelineOrderAllowEmptyValues ... + LogsPipelineOrderAllowEmptyValues = []string{} +) + +// LogsPipelineOrderGenerator ... +type LogsPipelineOrderGenerator struct { + DatadogService +} + +// InitResources Generate TerraformResources +func (g *LogsPipelineOrderGenerator) InitResources() error { + currentDate := time.Now().Format("20060102150405") + resourceName := fmt.Sprintf("logs_pipeline_order_%s", currentDate) + g.Resources = append(g.Resources, terraformutils.NewResource( + resourceName, + resourceName, + "datadog_logs_pipeline_order", + "datadog", + map[string]string{ + "name": resourceName, + }, + LogsPipelineOrderAllowEmptyValues, + map[string]interface{}{}, + )) + return nil +} diff --git a/providers/datadog/metric_metadata.go b/providers/datadog/metric_metadata.go new file mode 100644 index 000000000..e2489a047 --- /dev/null +++ b/providers/datadog/metric_metadata.go @@ -0,0 +1,69 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "fmt" + "log" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // MetricMetadataAllowEmptyValues ... + MetricMetadataAllowEmptyValues = []string{} +) + +// MetricMetadataGenerator ... +type MetricMetadataGenerator struct { + DatadogService +} + +func (g *MetricMetadataGenerator) createResource(metricName string) terraformutils.Resource { + return terraformutils.NewResource( + metricName, + fmt.Sprintf("metric_metadata_%s", metricName), + "datadog_metric_metadata", + "datadog", + map[string]string{ + "metric": metricName, + }, + MetricMetadataAllowEmptyValues, + map[string]interface{}{}, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each metric create 1 TerraformResource. +// Need Metric Name as ID for terraform resource +func (g *MetricMetadataGenerator) InitResources() error { + resources := []terraformutils.Resource{} + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("metric_metadata") { + for _, value := range filter.AcceptableValues { + resources = append(resources, g.createResource(value)) + } + } + } + + // Collecting all metrics_metadata can be an expensive task. + // Hence, only allow collections of metrics passed via filter + if len(resources) == 0 { + log.Print("Filter(metric names as IDs) is required for importing datadog_metric_metadata resource") + return nil + } + g.Resources = resources + return nil +} diff --git a/providers/datadog/monitor.go b/providers/datadog/monitor.go index c258133f3..2e9ccd1ca 100644 --- a/providers/datadog/monitor.go +++ b/providers/datadog/monitor.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "strconv" + "strings" datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" @@ -26,7 +27,7 @@ import ( var ( // MonitorAllowEmptyValues ... - MonitorAllowEmptyValues = []string{"tags."} + MonitorAllowEmptyValues = []string{"tags.", "message"} ) // MonitorGenerator ... @@ -64,6 +65,7 @@ func (g *MonitorGenerator) InitResources() error { datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) authV1 := g.Args["authV1"].(context.Context) + optionalParams := datadogV1.NewListMonitorsOptionalParameters() resources := []terraformutils.Resource{} for _, filter := range g.Filter { if filter.FieldPath == "id" && filter.IsApplicable("monitor") { @@ -73,7 +75,7 @@ func (g *MonitorGenerator) InitResources() error { return err } - monitor, _, err := datadogClientV1.MonitorsApi.GetMonitor(authV1, i).Execute() + monitor, _, err := datadogClientV1.MonitorsApi.GetMonitor(authV1, i) if err != nil { return err } @@ -81,6 +83,9 @@ func (g *MonitorGenerator) InitResources() error { resources = append(resources, g.createResource(strconv.FormatInt(monitor.GetId(), 10))) } } + if filter.FieldPath == "tags" && filter.IsApplicable("monitor") { + optionalParams.WithMonitorTags(strings.Join(filter.AcceptableValues, ",")) + } } if len(resources) > 0 { @@ -88,10 +93,26 @@ func (g *MonitorGenerator) InitResources() error { return nil } - monitors, _, err := datadogClientV1.MonitorsApi.ListMonitors(authV1).Execute() - if err != nil { - return err + var monitors []datadogV1.Monitor + pageSize := int32(1000) + pageNumber := int64(0) + for { + resp, _, err := datadogClientV1.MonitorsApi.ListMonitors(authV1, *optionalParams. + WithPageSize(pageSize). + WithPage(pageNumber)) + if err != nil { + return err + } + + if len(resp) == 0 || int32(len(resp)) < pageSize { + monitors = append(monitors, resp...) + break + } + + monitors = append(monitors, resp...) + pageNumber++ } + g.Resources = g.createResources(monitors) return nil } diff --git a/providers/datadog/role.go b/providers/datadog/role.go new file mode 100644 index 000000000..2008b6fff --- /dev/null +++ b/providers/datadog/role.go @@ -0,0 +1,85 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // RoleAllowEmptyValues ... + RoleAllowEmptyValues = []string{} +) + +// RoleGenerator ... +type RoleGenerator struct { + DatadogService +} + +func (g *RoleGenerator) createResources(roles []datadogV2.Role) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, role := range roles { + resourceName := role.GetId() + resource := g.createResource(resourceName) + resource.IgnoreKeys = append(resource.IgnoreKeys, "permission.([0-9]+).name") + resources = append(resources, resource) + } + + return resources +} + +func (g *RoleGenerator) createResource(roleID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + roleID, + fmt.Sprintf("role_%s", roleID), + "datadog_role", + "datadog", + RoleAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each role create 1 TerraformResource. +// Need Role ID as ID for terraform resource +func (g *RoleGenerator) InitResources() error { + datadogClientV2 := g.Args["datadogClientV2"].(*datadogV2.APIClient) + authV2 := g.Args["authV2"].(context.Context) + + pageSize := int64(100) + pageNumber := int64(0) + remaining := int64(1) + + var roles []datadogV2.Role + for remaining > int64(0) { + resp, _, err := datadogClientV2.RolesApi.ListRoles(authV2, *datadogV2.NewListRolesOptionalParameters(). + WithPageSize(pageSize). + WithPageNumber(pageNumber)) + if err != nil { + return err + } + roles = append(roles, resp.GetData()...) + + remaining = resp.Meta.Page.GetTotalCount() - pageSize*(pageNumber+1) + pageNumber++ + } + + g.Resources = g.createResources(roles) + return nil +} diff --git a/providers/datadog/screenboard.go b/providers/datadog/screenboard.go deleted file mode 100644 index 73e468e86..000000000 --- a/providers/datadog/screenboard.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The Terraformer Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package datadog - -import ( - "fmt" - "strconv" - - datadog "github.com/zorkian/go-datadog-api" - - "github.com/GoogleCloudPlatform/terraformer/terraformutils" -) - -var ( - // ScreenboardAllowEmptyValues ... - ScreenboardAllowEmptyValues = []string{"tags."} -) - -// ScreenboardGenerator ... -type ScreenboardGenerator struct { - DatadogService -} - -func (ScreenboardGenerator) createResources(screenboards []*datadog.ScreenboardLite) []terraformutils.Resource { - resources := []terraformutils.Resource{} - for _, screenboard := range screenboards { - resourceName := strconv.Itoa(screenboard.GetId()) - resources = append(resources, terraformutils.NewSimpleResource( - resourceName, - fmt.Sprintf("screenboard_%s", resourceName), - "datadog_screenboard", - "datadog", - ScreenboardAllowEmptyValues, - )) - } - - return resources -} - -// InitResources Generate TerraformResources from Datadog API, -// from each screenboard create 1 TerraformResource. -// Need Screenboard ID as ID for terraform resource -func (g *ScreenboardGenerator) InitResources() error { - client := datadog.NewClient(g.Args["api-key"].(string), g.Args["app-key"].(string)) - _, err := client.Validate() - if err != nil { - return err - } - screenboards, err := client.GetScreenboards() - if err != nil { - return err - } - g.Resources = g.createResources(screenboards) - return nil -} diff --git a/providers/datadog/security_monitoring_default_rule.go b/providers/datadog/security_monitoring_default_rule.go new file mode 100644 index 000000000..67a30a93a --- /dev/null +++ b/providers/datadog/security_monitoring_default_rule.go @@ -0,0 +1,87 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // SecurityMonitoringDefaultRuleAllowEmptyValues ... + SecurityMonitoringDefaultRuleAllowEmptyValues = []string{"tags."} +) + +// SecurityMonitoringDefaultRuleGenerator ... +type SecurityMonitoringDefaultRuleGenerator struct { + DatadogService +} + +func (g *SecurityMonitoringDefaultRuleGenerator) createResources(rulesResponse []datadogV2.SecurityMonitoringRuleResponse) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, rule := range rulesResponse { + if rule.GetIsDefault() { + resourceName := rule.GetId() + resources = append(resources, g.createResource(resourceName)) + } + } + + return resources +} + +func (g *SecurityMonitoringDefaultRuleGenerator) createResource(ruleID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + ruleID, + fmt.Sprintf("security_monitoring_default_rule_%s", ruleID), + "datadog_security_monitoring_default_rule", + "datadog", + SecurityMonitoringDefaultRuleAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each SecurityMonitoringDefaultRule create 1 TerraformResource. +// Need SecurityMonitoringDefaultRule ID as ID for terraform resource +func (g *SecurityMonitoringDefaultRuleGenerator) InitResources() error { + var securityMonitoringRuleResponses []datadogV2.SecurityMonitoringRuleResponse + + datadogClientV2 := g.Args["datadogClientV2"].(*datadogV2.APIClient) + authV2 := g.Args["authV2"].(context.Context) + + pageSize := int64(1000) + pageNumber := int64(0) + remaining := int64(1) + + for remaining > int64(0) { + resp, _, err := datadogClientV2.SecurityMonitoringApi.ListSecurityMonitoringRules(authV2, + *datadogV2.NewListSecurityMonitoringRulesOptionalParameters(). + WithPageSize(pageSize). + WithPageNumber(pageNumber)) + if err != nil { + return err + } + securityMonitoringRuleResponses = append(securityMonitoringRuleResponses, resp.GetData()...) + + remaining = resp.Meta.Page.GetTotalCount() - pageSize*(pageNumber+1) + pageNumber++ + } + + g.Resources = g.createResources(securityMonitoringRuleResponses) + return nil +} diff --git a/providers/datadog/security_monitoring_rule.go b/providers/datadog/security_monitoring_rule.go new file mode 100644 index 000000000..fe0e6744b --- /dev/null +++ b/providers/datadog/security_monitoring_rule.go @@ -0,0 +1,92 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + "strconv" + + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // SecurityMonitoringRuleAllowEmptyValues ... + SecurityMonitoringRuleAllowEmptyValues = []string{"tags."} +) + +// SecurityMonitoringRuleGenerator ... +type SecurityMonitoringRuleGenerator struct { + DatadogService +} + +func (g *SecurityMonitoringRuleGenerator) createResources(rulesResponse []datadogV2.SecurityMonitoringRuleResponse) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, rule := range rulesResponse { + if !rule.GetIsDefault() { + resourceName := rule.GetId() + resources = append(resources, g.createResource(resourceName, rule.GetIsEnabled())) + } + } + + return resources +} + +func (g *SecurityMonitoringRuleGenerator) createResource(ruleID string, ruleEnabled bool) terraformutils.Resource { + return terraformutils.NewResource( + ruleID, + fmt.Sprintf("security_monitoring_rule_%s", ruleID), + "datadog_security_monitoring_rule", + "datadog", + map[string]string{ + "enabled": strconv.FormatBool(ruleEnabled), + }, + SecurityMonitoringRuleAllowEmptyValues, + map[string]interface{}{}, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each SecurityMonitoringRule create 1 TerraformResource. +// Need SecurityMonitoringRule ID as ID for terraform resource +func (g *SecurityMonitoringRuleGenerator) InitResources() error { + var securityMonitoringRuleResponses []datadogV2.SecurityMonitoringRuleResponse + + datadogClientV2 := g.Args["datadogClientV2"].(*datadogV2.APIClient) + authV2 := g.Args["authV2"].(context.Context) + + pageSize := int64(1000) + pageNumber := int64(0) + remaining := int64(1) + + for remaining > int64(0) { + resp, _, err := datadogClientV2.SecurityMonitoringApi.ListSecurityMonitoringRules(authV2, + *datadogV2.NewListSecurityMonitoringRulesOptionalParameters(). + WithPageNumber(pageNumber). + WithPageSize(pageSize)) + if err != nil { + return err + } + securityMonitoringRuleResponses = append(securityMonitoringRuleResponses, resp.GetData()...) + + remaining = resp.Meta.Page.GetTotalCount() - pageSize*(pageNumber+1) + pageNumber++ + } + + g.Resources = g.createResources(securityMonitoringRuleResponses) + return nil +} diff --git a/providers/datadog/service_level_objective.go b/providers/datadog/service_level_objective.go new file mode 100644 index 000000000..7ed4c503c --- /dev/null +++ b/providers/datadog/service_level_objective.go @@ -0,0 +1,72 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // ServiceLevelObjectiveAllowEmptyValues ... + ServiceLevelObjectiveAllowEmptyValues = []string{"tags."} +) + +// ServiceLevelObjectiveGenerator ... +type ServiceLevelObjectiveGenerator struct { + DatadogService +} + +func (g *ServiceLevelObjectiveGenerator) createResources(sloList []datadogV1.ServiceLevelObjective) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, slo := range sloList { + resourceID := slo.GetId() + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *ServiceLevelObjectiveGenerator) createResource(sloID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + sloID, + fmt.Sprintf("service_level_objective_%s", sloID), + "datadog_service_level_objective", + "datadog", + ServiceLevelObjectiveAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each service_level_objective create 1 TerraformResource. +// Need ServiceLevelObjective ID as ID for terraform resource +func (g *ServiceLevelObjectiveGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + var slos []datadogV1.ServiceLevelObjective + resp, _, err := datadogClientV1.ServiceLevelObjectivesApi.ListSLOs(authV1) + if err != nil { + return err + } + + slos = append(slos, resp.GetData()...) + g.Resources = g.createResources(slos) + return nil +} diff --git a/providers/datadog/synthetics_global_variable.go b/providers/datadog/synthetics_global_variable.go new file mode 100644 index 000000000..4fcccb4ad --- /dev/null +++ b/providers/datadog/synthetics_global_variable.go @@ -0,0 +1,85 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + "log" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // SyntheticsGlobalVariableAllowEmptyValues ... + SyntheticsGlobalVariableAllowEmptyValues = []string{"tags."} +) + +// SyntheticsGlobalVariableGenerator ... +type SyntheticsGlobalVariableGenerator struct { + DatadogService +} + +func (g *SyntheticsGlobalVariableGenerator) createResources(globalVariables []datadogV1.SyntheticsGlobalVariable) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, globalVariable := range globalVariables { + resourceID := globalVariable.GetId() + resources = append(resources, g.createResource(resourceID)) + } + + return resources +} + +func (g *SyntheticsGlobalVariableGenerator) createResource(globalVariableID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + globalVariableID, + fmt.Sprintf("synthetics_global_variable_%s", globalVariableID), + "datadog_synthetics_global_variable", + "datadog", + SyntheticsGlobalVariableAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each SyntheticsGlobalVariable create 1 TerraformResource. +// Need SyntheticsGlobalVariable ID as ID for terraform resource +func (g *SyntheticsGlobalVariableGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + var globalVariableIDs []datadogV1.SyntheticsGlobalVariable + for _, filter := range g.Filter { + if filter.FieldPath == "id" && filter.IsApplicable("synthetics_global_variable") { + for _, v := range filter.AcceptableValues { + resp, _, err := datadogClientV1.SyntheticsApi.GetGlobalVariable(authV1, v) + if err != nil { + log.Printf("error retrieving synthetics gloval variable with id:%s - %s", v, err) + continue + } + globalVariableIDs = append(globalVariableIDs, resp) + } + } + } + + if len(globalVariableIDs) == 0 { + log.Print("Filter(Synthetics Global Variable IDs) is required for importing datadog_synthetics_global_variable resource") + return nil + } + + g.Resources = g.createResources(globalVariableIDs) + return nil +} diff --git a/providers/datadog/synthetics_private_location.go b/providers/datadog/synthetics_private_location.go new file mode 100644 index 000000000..a46b4eebd --- /dev/null +++ b/providers/datadog/synthetics_private_location.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datadog + +import ( + "context" + "fmt" + "regexp" + + datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +var ( + // SyntheticsPrivateLocationAllowEmptyValues ... + SyntheticsPrivateLocationAllowEmptyValues = []string{"tags."} + plIDRegex = regexp.MustCompile("^pl:.*") +) + +// SyntheticsPrivateLocationGenerator ... +type SyntheticsPrivateLocationGenerator struct { + DatadogService +} + +func (g *SyntheticsPrivateLocationGenerator) createResources(locations []datadogV1.SyntheticsLocation) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, location := range locations { + locationID := location.GetId() + if plIDRegex.MatchString(locationID) { + resources = append(resources, g.createResource(locationID)) + } + } + return resources +} + +func (g *SyntheticsPrivateLocationGenerator) createResource(plID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + plID, + fmt.Sprintf("synthetics_private_location_%s", plID), + "datadog_synthetics_private_location", + "datadog", + SyntheticsPrivateLocationAllowEmptyValues, + ) +} + +// InitResources Generate TerraformResources from Datadog API, +// from each SyntheticsPrivateLocation create 1 TerraformResource. +// Need SyntheticsPrivateLocation ID as ID for terraform resource +func (g *SyntheticsPrivateLocationGenerator) InitResources() error { + datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) + authV1 := g.Args["authV1"].(context.Context) + + data, _, err := datadogClientV1.SyntheticsApi.ListLocations(authV1) + if err != nil { + return err + } + + g.Resources = g.createResources(data.GetLocations()) + return nil +} diff --git a/providers/datadog/synthetics.go b/providers/datadog/synthetics_test_.go similarity index 84% rename from providers/datadog/synthetics.go rename to providers/datadog/synthetics_test_.go index 427aec9f7..a8659006c 100644 --- a/providers/datadog/synthetics.go +++ b/providers/datadog/synthetics_test_.go @@ -28,12 +28,12 @@ var ( SyntheticsAllowEmptyValues = []string{"tags."} ) -// SyntheticsGenerator ... -type SyntheticsGenerator struct { +// SyntheticsTestGenerator ... +type SyntheticsTestGenerator struct { DatadogService } -func (g *SyntheticsGenerator) createResources(syntheticsList []datadogV1.SyntheticsTestDetails) []terraformutils.Resource { +func (g *SyntheticsTestGenerator) createResources(syntheticsList []datadogV1.SyntheticsTestDetails) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, synthetics := range syntheticsList { resourceName := synthetics.GetPublicId() @@ -43,7 +43,7 @@ func (g *SyntheticsGenerator) createResources(syntheticsList []datadogV1.Synthet return resources } -func (g *SyntheticsGenerator) createResource(syntheticsID string) terraformutils.Resource { +func (g *SyntheticsTestGenerator) createResource(syntheticsID string) terraformutils.Resource { return terraformutils.NewSimpleResource( syntheticsID, fmt.Sprintf("synthetics_%s", syntheticsID), @@ -56,15 +56,15 @@ func (g *SyntheticsGenerator) createResource(syntheticsID string) terraformutils // InitResources Generate TerraformResources from Datadog API, // from each synthetics create 1 TerraformResource. // Need Synthetics ID as ID for terraform resource -func (g *SyntheticsGenerator) InitResources() error { +func (g *SyntheticsTestGenerator) InitResources() error { datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) authV1 := g.Args["authV1"].(context.Context) resources := []terraformutils.Resource{} for _, filter := range g.Filter { - if filter.FieldPath == "id" && filter.IsApplicable("synthetics") { + if filter.FieldPath == "id" && filter.IsApplicable("synthetics_test") { for _, value := range filter.AcceptableValues { - syntheticsTest, _, err := datadogClientV1.SyntheticsApi.GetTest(authV1, value).Execute() + syntheticsTest, _, err := datadogClientV1.SyntheticsApi.GetTest(authV1, value) if err != nil { return err } @@ -79,7 +79,7 @@ func (g *SyntheticsGenerator) InitResources() error { return nil } - syntheticsTests, _, err := datadogClientV1.SyntheticsApi.ListTests(authV1).Execute() + syntheticsTests, _, err := datadogClientV1.SyntheticsApi.ListTests(authV1) if err != nil { return err } diff --git a/providers/datadog/timeboard.go b/providers/datadog/timeboard.go deleted file mode 100644 index 1b1414415..000000000 --- a/providers/datadog/timeboard.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The Terraformer Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package datadog - -import ( - "fmt" - "strconv" - - datadog "github.com/zorkian/go-datadog-api" - - "github.com/GoogleCloudPlatform/terraformer/terraformutils" -) - -var ( - // TimeboardAllowEmptyValues ... - TimeboardAllowEmptyValues = []string{"tags."} -) - -// TimeboardGenerator ... -type TimeboardGenerator struct { - DatadogService -} - -func (TimeboardGenerator) createResources(timeboards []datadog.DashboardLite) []terraformutils.Resource { - resources := []terraformutils.Resource{} - for _, timeboard := range timeboards { - resourceName := strconv.Itoa(timeboard.GetId()) - resources = append(resources, terraformutils.NewSimpleResource( - resourceName, - fmt.Sprintf("timeboard_%s", resourceName), - "datadog_timeboard", - "datadog", - TimeboardAllowEmptyValues, - )) - } - - return resources -} - -// InitResources Generate TerraformResources from Datadog API, -// from each timeboard create 1 TerraformResource. -// Need Timeboard ID as ID for terraform resource -func (g *TimeboardGenerator) InitResources() error { - client := datadog.NewClient(g.Args["api-key"].(string), g.Args["app-key"].(string)) - _, err := client.Validate() - if err != nil { - return err - } - timeboards, err := client.GetDashboards() - if err != nil { - return err - } - g.Resources = g.createResources(timeboards) - return nil -} diff --git a/providers/datadog/user.go b/providers/datadog/user.go index 62ac939a4..5aaebaba9 100644 --- a/providers/datadog/user.go +++ b/providers/datadog/user.go @@ -17,10 +17,11 @@ package datadog import ( "context" "fmt" - - datadogV1 "github.com/DataDog/datadog-api-client-go/api/v1/datadog" + "strings" "github.com/GoogleCloudPlatform/terraformer/terraformutils" + + datadogV2 "github.com/DataDog/datadog-api-client-go/api/v2/datadog" ) var ( @@ -33,13 +34,21 @@ type UserGenerator struct { DatadogService } -func (g *UserGenerator) createResources(users []datadogV1.User) []terraformutils.Resource { +func (g *UserGenerator) createResources(users []datadogV2.User) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, user := range users { - resourceName := user.GetHandle() - resources = append(resources, g.createResource(resourceName)) - } + relations := user.GetRelationships() + roles := relations.GetRoles() + // If no roles are present, we can assume user was created via the V1 API + // Hence, import the user via their handle + if len(roles.GetData()) == 0 { + attr := user.GetAttributes() + resources = append(resources, g.createResource(attr.GetHandle())) + continue + } + resources = append(resources, g.createResource(user.GetId())) + } return resources } @@ -57,32 +66,35 @@ func (g *UserGenerator) createResource(userID string) terraformutils.Resource { // from each user create 1 TerraformResource. // Need User ID as ID for terraform resource func (g *UserGenerator) InitResources() error { - datadogClientV1 := g.Args["datadogClientV1"].(*datadogV1.APIClient) - authV1 := g.Args["authV1"].(context.Context) + var users []datadogV2.User + datadogClientV2 := g.Args["datadogClientV2"].(*datadogV2.APIClient) + authV2 := g.Args["authV2"].(context.Context) - resources := []terraformutils.Resource{} + pageSize := int64(1000) + pageNumber := int64(0) + remaining := int64(1) + optionalParams := datadogV2.NewListUsersOptionalParameters() for _, filter := range g.Filter { - if filter.FieldPath == "id" && filter.IsApplicable("user") { - for _, value := range filter.AcceptableValues { - user, _, err := datadogClientV1.UsersApi.GetUser(authV1, value).Execute() - if err != nil { - return err - } - - resources = append(resources, g.createResource(user.User.GetHandle())) + if filter.IsApplicable("user") && filter.FieldPath == "disabled" { + if len(filter.AcceptableValues) == 1 && strings.ToLower(filter.AcceptableValues[0]) == "false" { + optionalParams = optionalParams.WithFilterStatus("Active,Pending") } } } - if len(resources) > 0 { - g.Resources = resources - return nil - } + for remaining > int64(0) { + resp, _, err := datadogClientV2.UsersApi.ListUsers(authV2, *optionalParams. + WithPageSize(pageSize). + WithPageNumber(pageNumber)) + if err != nil { + return err + } + users = append(users, resp.GetData()...) - users, _, err := datadogClientV1.UsersApi.ListUsers(authV1).Execute() - if err != nil { - return err + remaining = resp.Meta.Page.GetTotalCount() - pageSize*(pageNumber+1) + pageNumber++ } - g.Resources = g.createResources(users.GetUsers()) + + g.Resources = g.createResources(users) return nil } diff --git a/providers/equinixmetal/device.go b/providers/equinixmetal/device.go new file mode 100644 index 000000000..923c4bb14 --- /dev/null +++ b/providers/equinixmetal/device.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/packethost/packngo" +) + +type DeviceGenerator struct { + EquinixMetalService +} + +func (g DeviceGenerator) listDevices(client *packngo.Client) ([]packngo.Device, error) { + devices, _, err := client.Devices.List(g.GetArgs()["project_id"].(string), nil) + if err != nil { + return nil, err + } + + return devices, nil +} + +func (g DeviceGenerator) createResources(deviceList []packngo.Device) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, device := range deviceList { + resources = append(resources, terraformutils.NewSimpleResource( + device.ID, + device.Hostname, + "metal_device", + "equinixmetal", + []string{})) + } + return resources +} + +func (g *DeviceGenerator) InitResources() error { + client := g.generateClient() + output, err := g.listDevices(client) + if err != nil { + return err + } + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/equinixmetal/equinixmetal_provider.go b/providers/equinixmetal/equinixmetal_provider.go new file mode 100644 index 000000000..8d2000ff1 --- /dev/null +++ b/providers/equinixmetal/equinixmetal_provider.go @@ -0,0 +1,79 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type EquinixMetalProvider struct { //nolint + terraformutils.Provider + authToken string + projectID string +} + +func (p *EquinixMetalProvider) Init(args []string) error { + if os.Getenv("PACKET_AUTH_TOKEN") == "" { + return errors.New("set PACKET_AUTH_TOKEN env var") + } + p.authToken = os.Getenv("PACKET_AUTH_TOKEN") + + if os.Getenv("METAL_PROJECT_ID") == "" { + return errors.New("set METAL_PROJECT_ID env var") + } + p.projectID = os.Getenv("METAL_PROJECT_ID") + + return nil +} + +func (p *EquinixMetalProvider) GetName() string { + return "metal" +} + +func (p *EquinixMetalProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{} +} + +func (EquinixMetalProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p *EquinixMetalProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "device": &DeviceGenerator{}, + "sshkey": &SSHKeyGenerator{}, + "spotmarketrequest": &SpotMarketRequestGenerator{}, + "volume": &VolumeGenerator{}, + } +} + +func (p *EquinixMetalProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New("equinixmetal: " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "auth_token": p.authToken, + "project_id": p.projectID, + }) + return nil +} diff --git a/providers/equinixmetal/equinixmetal_service.go b/providers/equinixmetal/equinixmetal_service.go new file mode 100644 index 000000000..3151ad59c --- /dev/null +++ b/providers/equinixmetal/equinixmetal_service.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/packethost/packngo" +) + +type EquinixMetalService struct { //nolint + terraformutils.Service +} + +func (s *EquinixMetalService) generateClient() *packngo.Client { + client, _ := packngo.NewClient() + return client +} diff --git a/providers/equinixmetal/spot_market_request.go b/providers/equinixmetal/spot_market_request.go new file mode 100644 index 000000000..61f85dddf --- /dev/null +++ b/providers/equinixmetal/spot_market_request.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/packethost/packngo" +) + +type SpotMarketRequestGenerator struct { + EquinixMetalService +} + +func (g SpotMarketRequestGenerator) listSpotMarketRequests(client *packngo.Client) ([]packngo.SpotMarketRequest, error) { + spotMarketRequests, _, err := client.SpotMarketRequests.List(g.GetArgs()["project_id"].(string), nil) + if err != nil { + return nil, err + } + + return spotMarketRequests, nil +} + +func (g SpotMarketRequestGenerator) createResources(spotMarketRequestsList []packngo.SpotMarketRequest) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, spotMarketRequests := range spotMarketRequestsList { + resources = append(resources, terraformutils.NewSimpleResource( + spotMarketRequests.ID, + spotMarketRequests.ID, + "metal_spot_market_request", + "equinixmetal", + []string{})) + } + return resources +} + +func (g *SpotMarketRequestGenerator) InitResources() error { + client := g.generateClient() + output, err := g.listSpotMarketRequests(client) + if err != nil { + return err + } + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/equinixmetal/ssh_key.go b/providers/equinixmetal/ssh_key.go new file mode 100644 index 000000000..bc08328bc --- /dev/null +++ b/providers/equinixmetal/ssh_key.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/packethost/packngo" +) + +type SSHKeyGenerator struct { + EquinixMetalService +} + +func (g SSHKeyGenerator) listSSHKeys(client *packngo.Client) ([]packngo.SSHKey, error) { + sshKeys, _, err := client.SSHKeys.List() + if err != nil { + return nil, err + } + + return sshKeys, nil +} + +func (g SSHKeyGenerator) createResources(sshLeyList []packngo.SSHKey) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, sshKey := range sshLeyList { + resources = append(resources, terraformutils.NewSimpleResource( + sshKey.ID, + sshKey.Label, + "metal_ssh_key", + "equinixmetal", + []string{})) + } + return resources +} + +func (g *SSHKeyGenerator) InitResources() error { + client := g.generateClient() + output, err := g.listSSHKeys(client) + if err != nil { + return err + } + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/equinixmetal/volume.go b/providers/equinixmetal/volume.go new file mode 100644 index 000000000..4c2f0a3ed --- /dev/null +++ b/providers/equinixmetal/volume.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package equinixmetal + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/packethost/packngo" +) + +type VolumeGenerator struct { + EquinixMetalService +} + +func (g VolumeGenerator) listVolumes(client *packngo.Client) ([]packngo.Volume, error) { + volumes, _, err := client.Volumes.List(g.GetArgs()["project_id"].(string), nil) + if err != nil { + return nil, err + } + + return volumes, nil +} + +func (g VolumeGenerator) createResources(volumeList []packngo.Volume) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, volume := range volumeList { + resources = append(resources, terraformutils.NewSimpleResource( + volume.ID, + volume.Name, + "metal_volume", + "equinixmetal", + []string{})) + } + return resources +} + +func (g *VolumeGenerator) InitResources() error { + client := g.generateClient() + output, err := g.listVolumes(client) + if err != nil { + return err + } + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/fastly/fastly_provider.go b/providers/fastly/fastly_provider.go index 7963f3d80..acbbd475a 100644 --- a/providers/fastly/fastly_provider.go +++ b/providers/fastly/fastly_provider.go @@ -61,8 +61,9 @@ func (FastlyProvider) GetResourceConnections() map[string]map[string][]string { func (p *FastlyProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { return map[string]terraformutils.ServiceGenerator{ - "service_v1": &ServiceV1Generator{}, - "user": &UserGenerator{}, + "service_v1": &ServiceV1Generator{}, + "tls_subscription": &TLSSubscriptionGenerator{}, + "user": &UserGenerator{}, } } diff --git a/providers/fastly/service_v1.go b/providers/fastly/service_v1.go index ace04cbf1..ab96b33a1 100644 --- a/providers/fastly/service_v1.go +++ b/providers/fastly/service_v1.go @@ -16,7 +16,14 @@ package fastly import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/fastly/go-fastly/fastly" + "github.com/fastly/go-fastly/v5/fastly" +) + +const ( + // ServiceTypeVCL is the type for VCL services. + ServiceTypeVCL = "vcl" + // ServiceTypeWasm is the type for Wasm services. + ServiceTypeWasm = "wasm" ) type ServiceV1Generator struct { @@ -29,26 +36,35 @@ func (g *ServiceV1Generator) loadServices(client *fastly.Client) ([]*fastly.Serv return nil, err } for _, service := range services { - g.Resources = append(g.Resources, terraformutils.NewSimpleResource( - service.ID, - service.ID, - "fastly_service_v1", - "fastly", - []string{})) + if service.Type == ServiceTypeVCL { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + service.ID, + service.ID, + "fastly_service_v1", + "fastly", + []string{})) + } else if service.Type == ServiceTypeWasm { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + service.ID, + service.ID, + "fastly_service_compute", + "fastly", + []string{})) + } } return services, nil } func (g *ServiceV1Generator) loadDictionaryItems(client *fastly.Client, serviceID string) error { latest, err := client.LatestVersion(&fastly.LatestVersionInput{ - Service: serviceID, + ServiceID: serviceID, }) if err != nil { return err } dictionaries, err := client.ListDictionaries(&fastly.ListDictionariesInput{ - Service: serviceID, - Version: latest.Number, + ServiceID: serviceID, + ServiceVersion: latest.Number, }) if err != nil { return err @@ -71,14 +87,14 @@ func (g *ServiceV1Generator) loadDictionaryItems(client *fastly.Client, serviceI func (g *ServiceV1Generator) loadACLEntries(client *fastly.Client, serviceID string) error { latest, err := client.LatestVersion(&fastly.LatestVersionInput{ - Service: serviceID, + ServiceID: serviceID, }) if err != nil { return err } acls, err := client.ListACLs(&fastly.ListACLsInput{ - Service: serviceID, - Version: latest.Number, + ServiceID: serviceID, + ServiceVersion: latest.Number, }) if err != nil { return err @@ -101,14 +117,14 @@ func (g *ServiceV1Generator) loadACLEntries(client *fastly.Client, serviceID str func (g *ServiceV1Generator) loadDynamicSnippetContent(client *fastly.Client, serviceID string) error { latest, err := client.LatestVersion(&fastly.LatestVersionInput{ - Service: serviceID, + ServiceID: serviceID, }) if err != nil { return err } snippets, err := client.ListSnippets(&fastly.ListSnippetsInput{ - Service: serviceID, - Version: latest.Number, + ServiceID: serviceID, + ServiceVersion: latest.Number, }) if err != nil { return err diff --git a/providers/fastly/tls_subscription.go b/providers/fastly/tls_subscription.go new file mode 100644 index 000000000..26e703766 --- /dev/null +++ b/providers/fastly/tls_subscription.go @@ -0,0 +1,78 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fastly + +import ( + "log" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/fastly/go-fastly/v5/fastly" +) + +type TLSSubscriptionGenerator struct { + FastlyService +} + +func (g *TLSSubscriptionGenerator) loadTLSSubscriptions(client *fastly.Client) ([]*fastly.TLSSubscription, error) { + subscriptions, err := client.ListTLSSubscriptions(&fastly.ListTLSSubscriptionsInput{}) + if err != nil { + return nil, err + } + for _, subscription := range subscriptions { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + subscription.ID, + subscription.ID, + "fastly_tls_subscription", + "fastly", + []string{})) + } + return subscriptions, nil +} + +func (g *TLSSubscriptionGenerator) loadTLSActivations(client *fastly.Client) ([]*fastly.TLSActivation, error) { + activations, err := client.ListTLSActivations(&fastly.ListTLSActivationsInput{}) + if err != nil { + return nil, err + } + for _, activation := range activations { + log.Println("certicate: ", activation.ID) + + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + activation.ID, + activation.ID, + "fastly_tls_activation", + "fastly", + []string{}, + )) + } + return activations, nil +} + +func (g *TLSSubscriptionGenerator) InitResources() error { + client, err := fastly.NewClient(g.Args["api_key"].(string)) + if err != nil { + return err + } + + if _, err := g.loadTLSSubscriptions(client); err != nil { + return err + } + + if _, err := g.loadTLSActivations(client); err != nil { + return err + } + + return nil +} diff --git a/providers/fastly/user.go b/providers/fastly/user.go index a055461f9..b2b735026 100644 --- a/providers/fastly/user.go +++ b/providers/fastly/user.go @@ -16,7 +16,7 @@ package fastly import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - "github.com/fastly/go-fastly/fastly" + "github.com/fastly/go-fastly/v5/fastly" ) type UserGenerator struct { diff --git a/providers/gcp/clouddns.go b/providers/gcp/clouddns.go index 15ea2f86b..4554349f9 100644 --- a/providers/gcp/clouddns.go +++ b/providers/gcp/clouddns.go @@ -116,10 +116,10 @@ func (g *CloudDNSGenerator) PostConvertHook() error { continue } if zoneID == resourceZone.InstanceState.ID { - g.Resources[i].Item["managed_zone"] = "${google_dns_managed_zone." + resourceZone.ResourceName + ".name}" + g.Resources[i].Item["managed_zone"] = "google_dns_managed_zone." + resourceZone.ResourceName + ".name" name := g.Resources[i].Item["name"].(string) name = strings.ReplaceAll(name, resourceZone.Item["dns_name"].(string), "") - g.Resources[i].Item["name"] = name + "${google_dns_managed_zone." + resourceZone.ResourceName + ".dns_name}" + g.Resources[i].Item["name"] = name + "google_dns_managed_zone." + resourceZone.ResourceName + ".dns_name" } } } diff --git a/providers/gcp/gcp_provider.go b/providers/gcp/gcp_provider.go index 656be50d7..57745dc11 100644 --- a/providers/gcp/gcp_provider.go +++ b/providers/gcp/gcp_provider.go @@ -17,6 +17,7 @@ package gcp import ( "context" "errors" + "log" "os" "github.com/GoogleCloudPlatform/terraformer/terraformutils" @@ -49,10 +50,12 @@ func GetRegions(project string) []string { func getRegion(project, regionName string) *compute.Region { computeService, err := compute.NewService(context.Background()) if err != nil { + log.Println(err) return &compute.Region{} } region, err := computeService.Regions.Get(project, regionName).Do() if err != nil { + log.Println(err) return &compute.Region{} } return region diff --git a/providers/github/github_organization.go b/providers/github/github_organization.go new file mode 100644 index 000000000..ab972fbd9 --- /dev/null +++ b/providers/github/github_organization.go @@ -0,0 +1,39 @@ +// Copyright 2020 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package github + +import ( + "context" +) + +type OrganizationGenerator struct { + GithubService +} + +// Generate TerraformResources from Github API +func (g *OrganizationGenerator) InitResources() error { + ctx := context.Background() + client, err := g.createClient() + if err != nil { + return err + } + + owner := g.Args["owner"].(string) + g.Resources = append(g.Resources, createMembershipsResources(ctx, client, owner)...) + g.Resources = append(g.Resources, createOrganizationBlocksResources(ctx, client, owner)...) + g.Resources = append(g.Resources, createOrganizationProjects(ctx, client, owner)...) + + return nil +} diff --git a/providers/github/github_provider.go b/providers/github/github_provider.go index 46e74b1cf..59e6f0c5f 100644 --- a/providers/github/github_provider.go +++ b/providers/github/github_provider.go @@ -24,8 +24,9 @@ import ( type GithubProvider struct { //nolint terraformutils.Provider - organization string - token string + owner string + token string + baseURL string } func (p GithubProvider) GetResourceConnections() map[string]map[string][]string { @@ -36,7 +37,7 @@ func (p GithubProvider) GetProviderData(arg ...string) map[string]interface{} { return map[string]interface{}{ "provider": map[string]interface{}{ "github": map[string]interface{}{ - "organization": p.organization, + "owner": p.owner, }, }, } @@ -44,14 +45,15 @@ func (p GithubProvider) GetProviderData(arg ...string) map[string]interface{} { func (p *GithubProvider) GetConfig() cty.Value { return cty.ObjectVal(map[string]cty.Value{ - "organization": cty.StringVal(p.organization), - "token": cty.StringVal(p.token), + "owner": cty.StringVal(p.owner), + "token": cty.StringVal(p.token), + "base_url": cty.StringVal(p.baseURL), }) } -// Init GithubProvider with organization +// Init GithubProvider with owner func (p *GithubProvider) Init(args []string) error { - p.organization = args[0] + p.owner = args[0] if len(args) < 2 { if os.Getenv("GITHUB_TOKEN") == "" { return errors.New("token requirement") @@ -60,6 +62,13 @@ func (p *GithubProvider) Init(args []string) error { } else { p.token = args[1] } + if len(args) > 2 { + if args[2] != "" { + p.baseURL = args[2] + } else { + p.baseURL = githubDefaultURL + } + } return nil } @@ -77,8 +86,9 @@ func (p *GithubProvider) InitService(serviceName string, verbose bool) error { p.Service.SetVerbose(verbose) p.Service.SetProviderName(p.GetName()) p.Service.SetArgs(map[string]interface{}{ - "organization": p.organization, - "token": p.token, + "owner": p.owner, + "token": p.token, + "base_url": p.baseURL, }) return nil } @@ -87,6 +97,7 @@ func (p *GithubProvider) InitService(serviceName string, verbose bool) error { func (p *GithubProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { return map[string]terraformutils.ServiceGenerator{ "members": &MembersGenerator{}, + "organization": &OrganizationGenerator{}, "organization_blocks": &OrganizationBlockGenerator{}, "organization_projects": &OrganizationProjectGenerator{}, "organization_webhooks": &OrganizationWebhooksGenerator{}, diff --git a/providers/github/github_service.go b/providers/github/github_service.go index 781e2f416..583aeb8e1 100644 --- a/providers/github/github_service.go +++ b/providers/github/github_service.go @@ -14,8 +14,42 @@ package github -import "github.com/GoogleCloudPlatform/terraformer/terraformutils" +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/google/go-github/v35/github" + "golang.org/x/oauth2" +) + +const githubDefaultURL = "https://api.github.com/" type GithubService struct { //nolint terraformutils.Service } + +func (g *GithubService) createClient() (*github.Client, error) { + if g.GetArgs()["base_url"].(string) == githubDefaultURL { + return g.createRegularClient(), nil + } + return g.createEnterpriseClient() +} + +func (g *GithubService) createRegularClient() *github.Client { + ctx := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: g.Args["token"].(string)}, + ) + tc := oauth2.NewClient(ctx, ts) + return github.NewClient(tc) +} + +func (g *GithubService) createEnterpriseClient() (*github.Client, error) { + ctx := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: g.Args["token"].(string)}, + ) + tc := oauth2.NewClient(ctx, ts) + baseURL := g.GetArgs()["base_url"].(string) + return github.NewEnterpriseClient(baseURL, baseURL, tc) +} diff --git a/providers/github/members.go b/providers/github/members.go index a6bc903a3..2ade47589 100644 --- a/providers/github/members.go +++ b/providers/github/members.go @@ -20,8 +20,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) // MembersGenerator holds GithubService struct of Terraform service information @@ -32,12 +31,19 @@ type MembersGenerator struct { // InitResources generates TerraformResources from Github API, func (g *MembersGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) + client, err := g.createClient() + if err != nil { + return err + } + + owner := g.Args["owner"].(string) + g.Resources = append(g.Resources, createMembershipsResources(ctx, client, owner)...) + + return nil +} - client := githubAPI.NewClient(tc) +func createMembershipsResources(ctx context.Context, client *githubAPI.Client, owner string) []terraformutils.Resource { + resources := []terraformutils.Resource{} opt := &githubAPI.ListMembersOptions{ ListOptions: githubAPI.ListOptions{PerPage: 100}, @@ -45,7 +51,7 @@ func (g *MembersGenerator) InitResources() error { // List all organization members for the authenticated user for { - members, resp, err := client.Organizations.ListMembers(ctx, g.Args["organization"].(string), opt) + members, resp, err := client.Organizations.ListMembers(ctx, owner, opt) if err != nil { log.Println(err) return nil @@ -53,14 +59,15 @@ func (g *MembersGenerator) InitResources() error { for _, member := range members { resource := terraformutils.NewSimpleResource( - g.Args["organization"].(string)+":"+member.GetLogin(), + owner+":"+member.GetLogin(), member.GetLogin(), "github_membership", "github", []string{}, ) resource.SlowQueryRequired = true - g.Resources = append(g.Resources, resource) + + resources = append(resources, resource) } if resp.NextPage == 0 { @@ -68,5 +75,6 @@ func (g *MembersGenerator) InitResources() error { } opt.Page = resp.NextPage } - return nil + + return resources } diff --git a/providers/github/organizationWebhooks.go b/providers/github/organizationWebhooks.go index e5ad848f7..2aa3f00a9 100644 --- a/providers/github/organizationWebhooks.go +++ b/providers/github/organizationWebhooks.go @@ -21,8 +21,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type OrganizationWebhooksGenerator struct { @@ -32,18 +31,16 @@ type OrganizationWebhooksGenerator struct { // Generate TerraformResources from Github API, func (g *OrganizationWebhooksGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := githubAPI.NewClient(tc) + client, err := g.createClient() + if err != nil { + return err + } opt := &githubAPI.ListOptions{PerPage: 100} // List all organization hooks for the authenticated user for { - hooks, resp, err := client.Organizations.ListHooks(ctx, g.Args["organization"].(string), opt) + hooks, resp, err := client.Organizations.ListHooks(ctx, g.Args["owner"].(string), opt) if err != nil { log.Println(err) return nil diff --git a/providers/github/organization_block.go b/providers/github/organization_block.go index 632cdbf15..fd7de4df1 100644 --- a/providers/github/organization_block.go +++ b/providers/github/organization_block.go @@ -20,8 +20,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type OrganizationBlockGenerator struct { @@ -31,18 +30,25 @@ type OrganizationBlockGenerator struct { // Generate TerraformResources from Github API, func (g *OrganizationBlockGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) + client, err := g.createClient() + if err != nil { + return err + } + + owner := g.Args["owner"].(string) + g.Resources = append(g.Resources, createOrganizationBlocksResources(ctx, client, owner)...) - client := githubAPI.NewClient(tc) + return nil +} + +func createOrganizationBlocksResources(ctx context.Context, client *githubAPI.Client, owner string) []terraformutils.Resource { + resources := []terraformutils.Resource{} opt := &githubAPI.ListOptions{PerPage: 100} // List all organization blocks for the authenticated user for { - blocks, resp, err := client.Organizations.ListBlockedUsers(ctx, g.Args["organization"].(string), opt) + blocks, resp, err := client.Organizations.ListBlockedUsers(ctx, owner, opt) if err != nil { log.Println(err) return nil @@ -57,7 +63,8 @@ func (g *OrganizationBlockGenerator) InitResources() error { []string{}, ) resource.SlowQueryRequired = true - g.Resources = append(g.Resources, resource) + + resources = append(resources, resource) } if resp.NextPage == 0 { @@ -65,5 +72,5 @@ func (g *OrganizationBlockGenerator) InitResources() error { } opt.Page = resp.NextPage } - return nil + return resources } diff --git a/providers/github/organization_project.go b/providers/github/organization_project.go index 143d765c9..d56f23c42 100644 --- a/providers/github/organization_project.go +++ b/providers/github/organization_project.go @@ -21,8 +21,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type OrganizationProjectGenerator struct { @@ -32,12 +31,19 @@ type OrganizationProjectGenerator struct { // Generate TerraformResources from Github API, func (g *OrganizationProjectGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) + client, err := g.createClient() + if err != nil { + return err + } + + owner := g.Args["owner"].(string) + g.Resources = append(g.Resources, createOrganizationProjects(ctx, client, owner)...) + + return nil +} - client := githubAPI.NewClient(tc) +func createOrganizationProjects(ctx context.Context, client *githubAPI.Client, owner string) []terraformutils.Resource { + resources := []terraformutils.Resource{} opt := &githubAPI.ProjectListOptions{ ListOptions: githubAPI.ListOptions{PerPage: 100}, @@ -45,7 +51,7 @@ func (g *OrganizationProjectGenerator) InitResources() error { // List all organization projects for the authenticated user for { - projects, resp, err := client.Organizations.ListProjects(ctx, g.Args["organization"].(string), opt) + projects, resp, err := client.Organizations.ListProjects(ctx, owner, opt) if err != nil { log.Println(err) return nil @@ -60,7 +66,7 @@ func (g *OrganizationProjectGenerator) InitResources() error { []string{}, ) resource.SlowQueryRequired = true - g.Resources = append(g.Resources, resource) + resources = append(resources, resource) } if resp.NextPage == 0 { @@ -68,5 +74,5 @@ func (g *OrganizationProjectGenerator) InitResources() error { } opt.Page = resp.NextPage } - return nil + return resources } diff --git a/providers/github/repositories.go b/providers/github/repositories.go index d8d84fd43..2a9432663 100644 --- a/providers/github/repositories.go +++ b/providers/github/repositories.go @@ -20,8 +20,7 @@ import ( "strconv" "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type RepositoriesGenerator struct { @@ -31,19 +30,17 @@ type RepositoriesGenerator struct { // Generate TerraformResources from github API, func (g *RepositoriesGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.GetArgs()["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := githubAPI.NewClient(tc) + client, err := g.createClient() + if err != nil { + return err + } opt := &githubAPI.RepositoryListByOrgOptions{ ListOptions: githubAPI.ListOptions{PerPage: 100}, } // list all repositories for the authenticated user for { - repos, resp, err := client.Repositories.ListByOrg(ctx, g.GetArgs()["organization"].(string), opt) + repos, resp, err := client.Repositories.ListByOrg(ctx, g.GetArgs()["owner"].(string), opt) if err != nil { log.Println(err) return nil @@ -75,7 +72,7 @@ func (g *RepositoriesGenerator) InitResources() error { func (g *RepositoriesGenerator) createRepositoryWebhookResources(ctx context.Context, client *githubAPI.Client, repo *githubAPI.Repository) []terraformutils.Resource { resources := []terraformutils.Resource{} - hooks, _, err := client.Repositories.ListHooks(ctx, g.GetArgs()["organization"].(string), repo.GetName(), nil) + hooks, _, err := client.Repositories.ListHooks(ctx, g.GetArgs()["owner"].(string), repo.GetName(), nil) if err != nil { log.Println(err) } @@ -97,7 +94,7 @@ func (g *RepositoriesGenerator) createRepositoryWebhookResources(ctx context.Con func (g *RepositoriesGenerator) createRepositoryBranchProtectionResources(ctx context.Context, client *githubAPI.Client, repo *githubAPI.Repository) []terraformutils.Resource { resources := []terraformutils.Resource{} - branches, _, err := client.Repositories.ListBranches(ctx, g.GetArgs()["organization"].(string), repo.GetName(), nil) + branches, _, err := client.Repositories.ListBranches(ctx, g.GetArgs()["owner"].(string), repo.GetName(), nil) if err != nil { log.Println(err) } @@ -117,14 +114,14 @@ func (g *RepositoriesGenerator) createRepositoryBranchProtectionResources(ctx co func (g *RepositoriesGenerator) createRepositoryCollaboratorResources(ctx context.Context, client *githubAPI.Client, repo *githubAPI.Repository) []terraformutils.Resource { resources := []terraformutils.Resource{} - collaborators, _, err := client.Repositories.ListCollaborators(ctx, g.GetArgs()["organization"].(string), repo.GetName(), nil) + collaborators, _, err := client.Repositories.ListCollaborators(ctx, g.GetArgs()["owner"].(string), repo.GetName(), nil) if err != nil { log.Println(err) } for _, collaborator := range collaborators { resources = append(resources, terraformutils.NewSimpleResource( - repo.GetName()+":"+collaborator.GetName(), - repo.GetName()+":"+collaborator.GetName(), + repo.GetName()+":"+collaborator.GetLogin(), + repo.GetName()+":"+collaborator.GetLogin(), "github_repository_collaborator", "github", []string{}, @@ -135,7 +132,7 @@ func (g *RepositoriesGenerator) createRepositoryCollaboratorResources(ctx contex func (g *RepositoriesGenerator) createRepositoryDeployKeyResources(ctx context.Context, client *githubAPI.Client, repo *githubAPI.Repository) []terraformutils.Resource { resources := []terraformutils.Resource{} - deployKeys, _, err := client.Repositories.ListKeys(ctx, g.GetArgs()["organization"].(string), repo.GetName(), nil) + deployKeys, _, err := client.Repositories.ListKeys(ctx, g.GetArgs()["owner"].(string), repo.GetName(), nil) if err != nil { log.Println(err) } diff --git a/providers/github/teams.go b/providers/github/teams.go index 142f95f2f..1290c27c2 100644 --- a/providers/github/teams.go +++ b/providers/github/teams.go @@ -21,8 +21,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type TeamsGenerator struct { @@ -49,7 +48,7 @@ func (g *TeamsGenerator) createTeamsResources(ctx context.Context, teams []*gith func (g *TeamsGenerator) createTeamMembersResources(ctx context.Context, team *githubAPI.Team, client *githubAPI.Client) []terraformutils.Resource { resources := []terraformutils.Resource{} - members, _, err := client.Teams.ListTeamMembers(ctx, team.GetID(), nil) + members, _, err := client.Teams.ListTeamMembersBySlug(ctx, g.Args["owner"].(string), team.GetSlug(), nil) if err != nil { log.Println(err) } @@ -67,7 +66,7 @@ func (g *TeamsGenerator) createTeamMembersResources(ctx context.Context, team *g func (g *TeamsGenerator) createTeamRepositoriesResources(ctx context.Context, team *githubAPI.Team, client *githubAPI.Client) []terraformutils.Resource { resources := []terraformutils.Resource{} - repos, _, err := client.Teams.ListTeamRepos(ctx, team.GetID(), nil) + repos, _, err := client.Teams.ListTeamReposBySlug(ctx, g.Args["owner"].(string), team.GetSlug(), nil) if err != nil { log.Println(err) } @@ -86,17 +85,15 @@ func (g *TeamsGenerator) createTeamRepositoriesResources(ctx context.Context, te // InitResources generates TerraformResources from Github API, func (g *TeamsGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := githubAPI.NewClient(tc) + client, err := g.createClient() + if err != nil { + return err + } opt := &githubAPI.ListOptions{PerPage: 1} for { - teams, resp, err := client.Teams.ListTeams(ctx, g.Args["organization"].(string), opt) + teams, resp, err := client.Teams.ListTeams(ctx, g.Args["owner"].(string), opt) if err != nil { log.Println(err) return nil diff --git a/providers/github/user_ssh_keys.go b/providers/github/user_ssh_keys.go index 1711935db..441df005d 100644 --- a/providers/github/user_ssh_keys.go +++ b/providers/github/user_ssh_keys.go @@ -21,8 +21,7 @@ import ( "github.com/GoogleCloudPlatform/terraformer/terraformutils" - githubAPI "github.com/google/go-github/v25/github" - "golang.org/x/oauth2" + githubAPI "github.com/google/go-github/v35/github" ) type UserSSHKeyGenerator struct { @@ -32,12 +31,10 @@ type UserSSHKeyGenerator struct { // Generate TerraformResources from Github API, func (g *UserSSHKeyGenerator) InitResources() error { ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: g.Args["token"].(string)}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := githubAPI.NewClient(tc) + client, err := g.createClient() + if err != nil { + return err + } opt := &githubAPI.ListOptions{PerPage: 100} diff --git a/providers/gitlab/gitlab_provider.go b/providers/gitlab/gitlab_provider.go new file mode 100644 index 000000000..02720dc0c --- /dev/null +++ b/providers/gitlab/gitlab_provider.go @@ -0,0 +1,103 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/pkg/errors" + "github.com/zclconf/go-cty/cty" +) + +type GitLabProvider struct { //nolint + terraformutils.Provider + group string + token string + baseURL string +} + +func (p GitLabProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p GitLabProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "gitlab": map[string]interface{}{ + // TODO: Should I add some default config here? + // "token": p.token, + // "base_url": p.baseURL, + }, + }, + } +} + +func (p *GitLabProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "token": cty.StringVal(p.token), + // NOTE: Real provider doesn't support empty/null base_url, only set when there's value + "base_url": cty.StringVal(p.baseURL), + }) +} + +// Init GitLabProvider with group +func (p *GitLabProvider) Init(args []string) error { + p.group = args[0] + p.baseURL = gitLabDefaultURL + if len(args) < 2 { + if os.Getenv("GITLAB_TOKEN") == "" { + return errors.New("token requirement") + } + p.token = os.Getenv("GITLAB_TOKEN") + } else { + p.token = args[1] + } + if len(args) > 2 { + if args[2] != "" { + p.baseURL = args[2] + } + } + return nil +} + +func (p *GitLabProvider) GetName() string { + return "gitlab" +} + +func (p *GitLabProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "group": p.group, + "token": p.token, + "base_url": p.baseURL, + }) + return nil +} + +// GetSupportedService return map of support service for gitlab +func (p *GitLabProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "projects": &ProjectGenerator{}, + "groups": &GroupGenerator{}, + } +} diff --git a/providers/gitlab/gitlab_service.go b/providers/gitlab/gitlab_service.go new file mode 100644 index 000000000..2bbcdf8af --- /dev/null +++ b/providers/gitlab/gitlab_service.go @@ -0,0 +1,41 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/xanzy/go-gitlab" +) + +const gitLabDefaultURL = "https://gitlab.com/api/v4/" + +type GitLabService struct { //nolint + terraformutils.Service +} + +func (g *GitLabService) createClient() (*gitlab.Client, error) { + if g.GetArgs()["base_url"].(string) == gitLabDefaultURL { + return g.createRegularClient() + } + return g.createEnterpriseClient() +} + +func (g *GitLabService) createRegularClient() (*gitlab.Client, error) { + return gitlab.NewClient(g.Args["token"].(string)) +} + +func (g *GitLabService) createEnterpriseClient() (*gitlab.Client, error) { + return gitlab.NewClient(g.Args["token"].(string), gitlab.WithBaseURL(g.GetArgs()["base_url"].(string))) +} diff --git a/providers/gitlab/group.go b/providers/gitlab/group.go new file mode 100644 index 000000000..f3625ad55 --- /dev/null +++ b/providers/gitlab/group.go @@ -0,0 +1,138 @@ +// Copyright 2020 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/xanzy/go-gitlab" +) + +type GroupGenerator struct { + GitLabService +} + +// Generate TerraformResources from gitlab API, +func (g *GroupGenerator) InitResources() error { + ctx := context.Background() + client, err := g.createClient() + if err != nil { + return err + } + + group := g.Args["group"].(string) + g.Resources = append(g.Resources, createGroups(ctx, client, group)...) + + return nil +} + +func createGroups(ctx context.Context, client *gitlab.Client, groupID string) []terraformutils.Resource { + resources := []terraformutils.Resource{} + group, _, err := client.Groups.GetGroup(groupID, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + resource := terraformutils.NewSimpleResource( + strconv.FormatInt(int64(group.ID), 10), + getGroupResourceName(group), + "gitlab_group", + "gitlab", + []string{}, + ) + + // NOTE: mirror fields from API doesn't match with the ones from terraform provider + resource.IgnoreKeys = []string{"mirror_trigger_builds", "only_mirror_protected_branches", "mirror", "mirror_overwrites_diverged_branches"} + + resource.SlowQueryRequired = true + resources = append(resources, resource) + resources = append(resources, createGroupVariables(ctx, client, group)...) + resources = append(resources, createGroupMembership(ctx, client, group)...) + + return resources +} +func createGroupVariables(ctx context.Context, client *gitlab.Client, group *gitlab.Group) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListGroupVariablesOptions{} + + for { + groupVariables, resp, err := client.GroupVariables.ListVariables(group.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, groupVariable := range groupVariables { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%s:%s", group.ID, groupVariable.Key, groupVariable.EnvironmentScope), + fmt.Sprintf("%s___%s___%s", getGroupResourceName(group), groupVariable.Key, groupVariable.EnvironmentScope), + "gitlab_group_variable", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func createGroupMembership(ctx context.Context, client *gitlab.Client, group *gitlab.Group) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListGroupMembersOptions{} + + for { + groupMembers, resp, err := client.Groups.ListGroupMembers(group.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, groupMember := range groupMembers { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%d", group.ID, groupMember.ID), + fmt.Sprintf("%s___%s", getGroupResourceName(group), groupMember.Username), + "gitlab_group_membership", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func getGroupResourceName(group *gitlab.Group) string { + return fmt.Sprintf("%d___%s", group.ID, strings.ReplaceAll(group.FullPath, "/", "__")) +} diff --git a/providers/gitlab/project.go b/providers/gitlab/project.go new file mode 100644 index 000000000..2c5d04f48 --- /dev/null +++ b/providers/gitlab/project.go @@ -0,0 +1,218 @@ +// Copyright 2020 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/xanzy/go-gitlab" +) + +type ProjectGenerator struct { + GitLabService +} + +// Generate TerraformResources from gitlab API, +func (g *ProjectGenerator) InitResources() error { + ctx := context.Background() + client, err := g.createClient() + if err != nil { + return err + } + + group := g.Args["group"].(string) + g.Resources = append(g.Resources, createProjects(ctx, client, group)...) + + return nil +} + +func createProjects(ctx context.Context, client *gitlab.Client, group string) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListGroupProjectsOptions{ + ListOptions: gitlab.ListOptions{ + PerPage: 100, + }, + } + + for { + projects, resp, err := client.Groups.ListGroupProjects(group, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, project := range projects { + resource := terraformutils.NewSimpleResource( + strconv.FormatInt(int64(project.ID), 10), + getProjectResourceName(project), + "gitlab_project", + "gitlab", + []string{}, + ) + + // NOTE: mirror fields from API doesn't match with the ones from terraform provider + resource.IgnoreKeys = []string{"mirror_trigger_builds", "only_mirror_protected_branches", "mirror", "mirror_overwrites_diverged_branches"} + + resource.SlowQueryRequired = true + resources = append(resources, resource) + resources = append(resources, createProjectVariables(ctx, client, project)...) + resources = append(resources, createBranchProtections(ctx, client, project)...) + resources = append(resources, createTagProtections(ctx, client, project)...) + resources = append(resources, createProjectMembership(ctx, client, project)...) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} +func createProjectVariables(ctx context.Context, client *gitlab.Client, project *gitlab.Project) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListProjectVariablesOptions{} + + for { + projectVariables, resp, err := client.ProjectVariables.ListVariables(project.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, projectVariable := range projectVariables { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%s:%s", project.ID, projectVariable.Key, projectVariable.EnvironmentScope), + fmt.Sprintf("%s___%s___%s", getProjectResourceName(project), projectVariable.Key, projectVariable.EnvironmentScope), + "gitlab_project_variable", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func createBranchProtections(ctx context.Context, client *gitlab.Client, project *gitlab.Project) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListProtectedBranchesOptions{} + + for { + protectedBranches, resp, err := client.ProtectedBranches.ListProtectedBranches(project.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, protectedBranch := range protectedBranches { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%s", project.ID, protectedBranch.Name), + fmt.Sprintf("%s___%s", getProjectResourceName(project), protectedBranch.Name), + "gitlab_branch_protection", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func createTagProtections(ctx context.Context, client *gitlab.Client, project *gitlab.Project) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListProtectedTagsOptions{} + + for { + protectedTags, resp, err := client.ProtectedTags.ListProtectedTags(project.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, protectedTag := range protectedTags { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%s", project.ID, protectedTag.Name), + fmt.Sprintf("%s___%s", getProjectResourceName(project), protectedTag.Name), + "gitlab_tag_protection", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func createProjectMembership(ctx context.Context, client *gitlab.Client, project *gitlab.Project) []terraformutils.Resource { + resources := []terraformutils.Resource{} + opt := &gitlab.ListProjectMembersOptions{} + + for { + projectMembers, resp, err := client.ProjectMembers.ListProjectMembers(project.ID, opt, gitlab.WithContext(ctx)) + if err != nil { + log.Println(err) + return nil + } + + for _, projectMember := range projectMembers { + + resource := terraformutils.NewSimpleResource( + fmt.Sprintf("%d:%d", project.ID, projectMember.ID), + fmt.Sprintf("%s___%s", getProjectResourceName(project), projectMember.Username), + "gitlab_project_membership", + "gitlab", + []string{}, + ) + resource.SlowQueryRequired = true + resources = append(resources, resource) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + return resources +} + +func getProjectResourceName(project *gitlab.Project) string { + return fmt.Sprintf("%d___%s", project.ID, strings.ReplaceAll(project.PathWithNamespace, "/", "__")) +} diff --git a/providers/grafana/dashboard.go b/providers/grafana/dashboard.go new file mode 100644 index 000000000..8e1c83b39 --- /dev/null +++ b/providers/grafana/dashboard.go @@ -0,0 +1,67 @@ +package grafana + +import ( + "encoding/json" + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + gapi "github.com/grafana/grafana-api-golang-client" +) + +type DashboardGenerator struct { + GrafanaService +} + +func (g *DashboardGenerator) InitResources() error { + client, err := g.buildClient() + if err != nil { + return fmt.Errorf("unable to build grafana client: %v", err) + } + + err = g.createDashboardResources(client) + if err != nil { + return err + } + + return nil +} + +func (g *DashboardGenerator) createDashboardResources(client *gapi.Client) error { + dashboards, err := client.Dashboards() + if err != nil { + return fmt.Errorf("unable to list grafana dashboards: %v", err) + } + + for _, dashboard := range dashboards { + // search result doesn't include slug, so need to look up dashboard. + dash, err := client.DashboardByUID(dashboard.UID) + if err != nil { + return fmt.Errorf("unable to read grafana dashboard %s: %v", dashboard.Title, err) + } + + configJSON, err := json.MarshalIndent(dash.Model, "", " ") + if err != nil { + return fmt.Errorf("unable to marshal configuration for grafana dashboard %s: %v", dashboard.Title, err) + } + + filename := fmt.Sprintf("dashboard-%s.json", dash.Meta.Slug) + resource := terraformutils.NewResource( + dashboard.UID, + dashboard.Title, + "grafana_dashboard", + "grafana", + map[string]string{}, + []string{}, + map[string]interface{}{ + "config_json": fmt.Sprintf("file(\"data/%s\")", filename), + "folder": dashboard.FolderID, + }, + ) + resource.DataFiles = map[string][]byte{ + filename: configJSON, + } + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/grafana/folder.go b/providers/grafana/folder.go new file mode 100644 index 000000000..4ccb5cc4d --- /dev/null +++ b/providers/grafana/folder.go @@ -0,0 +1,49 @@ +package grafana + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + gapi "github.com/grafana/grafana-api-golang-client" +) + +type FolderGenerator struct { + GrafanaService +} + +func (g *FolderGenerator) InitResources() error { + client, err := g.buildClient() + if err != nil { + return fmt.Errorf("unable to build grafana client: %v", err) + } + + err = g.createFolderResources(client) + if err != nil { + return err + } + + return nil +} + +func (g *FolderGenerator) createFolderResources(client *gapi.Client) error { + folders, err := client.Folders() + if err != nil { + return fmt.Errorf("unable to list grafana folders: %v", err) + } + + for _, folder := range folders { + g.Resources = append(g.Resources, terraformutils.NewResource( + fmt.Sprint(folder.ID), + folder.Title, + "grafana_folder", + "grafana", + map[string]string{ + "uid": folder.UID, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return nil +} diff --git a/providers/grafana/grafana_provider.go b/providers/grafana/grafana_provider.go new file mode 100644 index 000000000..273997ce9 --- /dev/null +++ b/providers/grafana/grafana_provider.go @@ -0,0 +1,132 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grafana + +import ( + "os" + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/pkg/errors" + "github.com/zclconf/go-cty/cty" +) + +type GrafanaProvider struct { //nolint + terraformutils.Provider + auth string + url string + orgID int + tlsKey string + tlsCert string + caCert string + insecureSkipVerify bool +} + +func (p GrafanaProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{ + "grafana_dashboard": { + "grafana_folder": []string{"folder", "id"}, + }, + } +} + +func (p GrafanaProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "grafana": map[string]interface{}{ + "org_id": p.orgID, + "url": p.url, + "auth": p.auth, + "tls_key": p.tlsKey, + "tls_cert": p.tlsCert, + "ca_cert": p.caCert, + "insecure_skip_verify": p.insecureSkipVerify, + }, + }, + } +} + +func (p *GrafanaProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "org_id": cty.NumberIntVal(int64(p.orgID)), + "url": cty.StringVal(p.url), + "auth": cty.StringVal(p.auth), + "tls_key": cty.StringVal(p.tlsKey), + "tls_cert": cty.StringVal(p.tlsCert), + "ca_cert": cty.StringVal(p.caCert), + "insecure_skip_verify": cty.BoolVal(p.insecureSkipVerify), + }) +} + +func (p *GrafanaProvider) Init(args []string) error { + p.auth = os.Getenv("GRAFANA_AUTH") + if p.auth == "" { + return errors.New("Grafana API authentication must be set through `GRAFANA_AUTH` env var, either as an API token or as username:password for HTTP basic auth") + } + + p.url = os.Getenv("GRAFANA_URL") + if p.url == "" { + return errors.New("Grafana API URL must be set through `GRAFANA_URL` env var") + } + + orgID, err := strconv.Atoi(os.Getenv("GRAFANA_ORG_ID")) + if err != nil { + orgID = 1 + } + p.orgID = orgID + + p.tlsKey = os.Getenv("HTTPS_TLS_KEY") + p.tlsCert = os.Getenv("HTTPS_TLS_CERT") + p.caCert = os.Getenv("HTTPS_CA_CERT") + + if os.Getenv("HTTPS_INSECURE_SKIP_VERIFY") == "1" { + p.insecureSkipVerify = true + } + + return nil +} + +func (p *GrafanaProvider) GetName() string { + return "grafana" +} + +func (p *GrafanaProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "org_id": p.orgID, + "url": p.url, + "auth": p.auth, + "tls_key": p.tlsKey, + "tls_cert": p.tlsCert, + "ca_cert": p.caCert, + "insecure_skip_verify": p.insecureSkipVerify, + }) + return nil +} + +func (p *GrafanaProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "grafana_dashboard": &DashboardGenerator{}, + "grafana_folder": &FolderGenerator{}, + } +} diff --git a/providers/grafana/grafana_service.go b/providers/grafana/grafana_service.go new file mode 100644 index 000000000..8ceff5866 --- /dev/null +++ b/providers/grafana/grafana_service.go @@ -0,0 +1,86 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grafana + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "net/url" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + gapi "github.com/grafana/grafana-api-golang-client" + "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/terraform/helper/logging" +) + +type GrafanaService struct { //nolint + terraformutils.Service +} + +func (s *GrafanaService) buildClient() (*gapi.Client, error) { + auth := strings.SplitN(s.Args["auth"].(string), ":", 2) + cli := cleanhttp.DefaultClient() + transport := cleanhttp.DefaultTransport() + transport.TLSClientConfig = &tls.Config{} + + // TLS Config + tlsKey := s.Args["tls_key"].(string) + tlsCert := s.Args["tls_cert"].(string) + caCert := s.Args["ca_cert"].(string) + insecure := s.Args["insecure_skip_verify"].(bool) + + if caCert != "" { + ca, err := ioutil.ReadFile(caCert) + if err != nil { + return nil, err + } + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(ca) + transport.TLSClientConfig.RootCAs = pool + } + + if tlsKey != "" && tlsCert != "" { + cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey) + if err != nil { + return nil, err + } + transport.TLSClientConfig.Certificates = []tls.Certificate{cert} + } + + if insecure { + transport.TLSClientConfig.InsecureSkipVerify = true + } + + cli.Transport = logging.NewTransport("Grafana", transport) + cfg := gapi.Config{ + Client: cli, + OrgID: int64(s.Args["org_id"].(int)), + } + + if len(auth) == 2 { + cfg.BasicAuth = url.UserPassword(auth[0], auth[1]) + } else { + cfg.APIKey = auth[0] + } + + client, err := gapi.New(s.Args["url"].(string), cfg) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/providers/ibm/cis.go b/providers/ibm/cis.go new file mode 100644 index 000000000..197f03fb7 --- /dev/null +++ b/providers/ibm/cis.go @@ -0,0 +1,872 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "strconv" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM/go-sdk-core/v3/core" + "github.com/IBM/networking-go-sdk/custompagesv1" + "github.com/IBM/networking-go-sdk/dnsrecordsv1" + "github.com/IBM/networking-go-sdk/edgefunctionsapiv1" + "github.com/IBM/networking-go-sdk/filtersv1" + "github.com/IBM/networking-go-sdk/globalloadbalancermonitorv1" + "github.com/IBM/networking-go-sdk/globalloadbalancerpoolsv0" + "github.com/IBM/networking-go-sdk/globalloadbalancerv1" + "github.com/IBM/networking-go-sdk/pageruleapiv1" + "github.com/IBM/networking-go-sdk/rangeapplicationsv1" + "github.com/IBM/networking-go-sdk/routingv1" + "github.com/IBM/networking-go-sdk/sslcertificateapiv1" + "github.com/IBM/networking-go-sdk/useragentblockingrulesv1" + "github.com/IBM/networking-go-sdk/wafrulegroupsapiv1" + "github.com/IBM/networking-go-sdk/wafrulepackagesapiv1" + "github.com/IBM/networking-go-sdk/zonefirewallaccessrulesv1" + "github.com/IBM/networking-go-sdk/zonelockdownv1" + "github.com/IBM/networking-go-sdk/zoneratelimitsv1" + "github.com/IBM/networking-go-sdk/zonesv1" +) + +// CISGenerator .. +type CISGenerator struct { + IBMService +} + +func (g CISGenerator) loadInstances(crn, name, resGrpID string) terraformutils.Resource { + resource := terraformutils.NewResource( + crn, + normalizeResourceName(name, false), + "ibm_cis", + "ibm", + map[string]string{ + "resource_group_id": resGrpID, + }, + []string{}, + map[string]interface{}{}) + return resource +} + +func (g CISGenerator) loadDomains(crn, domainID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", domainID, crn), + normalizeResourceName("ibm_cis_domain", true), + "ibm_cis_domain", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadDNSRecords(crn, domainID, dnsRecordID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", dnsRecordID, domainID, crn), + normalizeResourceName("ibm_cis_dns_record", true), + "ibm_cis_dns_record", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g CISGenerator) loadFirewall(crn, domainID, fID, fType string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s:%s", fType, fID, domainID, crn), + normalizeResourceName("ibm_cis_firewall", true), + "ibm_cis_firewall", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadDomainSettings(crn, dID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", dID, crn), + normalizeResourceName("ibm_cis_domain_settings", true), + "ibm_cis_domain_settings", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadGlobalBalancer(crn, dID, gID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", gID, dID, crn), + normalizeResourceName("ibm_cis_global_load_balancer", true), + "ibm_cis_global_load_balancer", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + + // Conflicts with proxied attribute + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^ttl$", + ) + return resource +} + +func (g CISGenerator) loadGlobalBalancerPool(crn, pID, pName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", pID, crn), + normalizeResourceName(pName, true), + "ibm_cis_origin_pool", + g.ProviderName, + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadGlobalBalancerMonitor(crn, gblmID, port string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", gblmID, crn), + normalizeResourceName("ibm_cis_healthcheck", true), + "ibm_cis_healthcheck", + "ibm", + map[string]string{ + "port": port, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadRateLimit(crn, dID, rID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", rID, dID, crn), + normalizeResourceName("ibm_cis_rate_limit", true), + "ibm_cis_rate_limit", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadEdgeFunctionAction(crn, dID, actionID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", actionID, dID, crn), + normalizeResourceName("ibm_cis_edge_functions_action", true), + "ibm_cis_edge_functions_action", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadEdgeFunctionTrigger(crn, dID, triggerID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", triggerID, dID, crn), + normalizeResourceName("ibm_cis_edge_functions_trigger", true), + "ibm_cis_edge_functions_trigger", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadWafRulePackage(crn, dID, pkgID, actionMode, sensitivity string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", pkgID, dID, crn), + normalizeResourceName("ibm_cis_waf_package", true), + "ibm_cis_waf_package", + "ibm", + map[string]string{ + "action_mode": actionMode, + "sensitivity": sensitivity, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadWafGroups(crn, dID, pkgID, grpID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s:%s", grpID, pkgID, dID, crn), + normalizeResourceName("ibm_cis_waf_group", true), + "ibm_cis_waf_group", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadPageRule(crn, dID, ruleID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", ruleID, dID, crn), + normalizeResourceName("ibm_cis_page_rule", true), + "ibm_cis_page_rule", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadCustomPage(crn, dID, cpID, url string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", cpID, dID, crn), + normalizeResourceName("ibm_cis_custom_page", true), + "ibm_cis_custom_page", + "ibm", + map[string]string{ + "url": url, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadRangeApp(crn, dID, appID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", appID, dID, crn), + normalizeResourceName("ibm_cis_range_app", true), + "ibm_cis_range_app", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadSSLCertificates(crn, dID, cID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", cID, dID, crn), + normalizeResourceName("ibm_cis_certificate_order", true), + "ibm_cis_certificate_order", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadCISRouting(crn, dID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", dID, crn), + normalizeResourceName("ibm_cis_routing", true), + "ibm_cis_routing", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadCacheSettings(crn, dID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", dID, crn), + normalizeResourceName("ibm_cis_cache_settings", true), + "ibm_cis_cache_settings", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadTLSSettings(crn, dID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", dID, crn), + normalizeResourceName("ibm_cis_tls_settings", true), + "ibm_cis_tls_settings", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g CISGenerator) loadFilters(crn, dID, fID string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s:%s", fID, dID, crn), + normalizeResourceName("ibm_cis_filter", true), + "ibm_cis_filter", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +// InitResources .. +func (g *CISGenerator) InitResources() error { + DefaultCisURL := "https://api.cis.cloud.ibm.com" + + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + err = authenticateAPIKey(sess) + if err != nil { + return err + } + + bluemixToken := "" + if strings.HasPrefix(sess.Config.IAMAccessToken, "Bearer") { + bluemixToken = sess.Config.IAMAccessToken[7:len(sess.Config.IAMAccessToken)] + } else { + bluemixToken = sess.Config.IAMAccessToken + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("internet-svcs", true) + if err != nil { + return err + } + + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + cisInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + + for _, c := range cisInstances { + // Instance + crn := c.Crn.String() + g.Resources = append(g.Resources, g.loadInstances(crn, c.Name, c.ResourceGroupID)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + + var cisDependsOn []string + cisDependsOn = append(cisDependsOn, + "ibm_cis."+resourceName) + + // Domain + zoneOpts := &zonesv1.ZonesV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + } + + zService, err := zonesv1.NewZonesV1(zoneOpts) + if err != nil { + return err + } + + domainOpts := zService.NewListZonesOptions() + domainOpts.SetPage(1) // list all zones in one page + domainOpts.SetPerPage(1000) // maximum allowed limit is 1000 per page + + zoneList, _, err := zService.ListZones(domainOpts) + if err != nil { + return err + } + + // Origin pool + gblOpts := &globalloadbalancerpoolsv0.GlobalLoadBalancerPoolsV0Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{BearerToken: bluemixToken}, + Crn: &crn, + } + + gblService, err := globalloadbalancerpoolsv0.NewGlobalLoadBalancerPoolsV0(gblOpts) + if err != nil { + return err + } + + gblPoolList, _, err := gblService.ListAllLoadBalancerPools(&globalloadbalancerpoolsv0.ListAllLoadBalancerPoolsOptions{}) + if err != nil { + return err + } + + for _, gbl := range gblPoolList.Result { + if gbl.ID != nil { + g.Resources = append(g.Resources, g.loadGlobalBalancerPool(crn, *gbl.ID, *gbl.Name, cisDependsOn)) + } + } + + // Health Monitor + gblmOpts := &globalloadbalancermonitorv1.GlobalLoadBalancerMonitorV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{BearerToken: bluemixToken}, + Crn: &crn, + } + + gblmService, err := globalloadbalancermonitorv1.NewGlobalLoadBalancerMonitorV1(gblmOpts) + if err != nil { + return err + } + + gblmList, _, err := gblmService.ListAllLoadBalancerMonitors(&globalloadbalancermonitorv1.ListAllLoadBalancerMonitorsOptions{}) + if err != nil { + return err + } + for _, gblm := range gblmList.Result { + if gblm.Port != nil { + port := strconv.FormatInt(*gblm.Port, 10) + g.Resources = append(g.Resources, g.loadGlobalBalancerMonitor(crn, *gblm.ID, port, cisDependsOn)) + } + } + + for _, z := range zoneList.Result { + var domainDependsOn []string + domainDependsOn = append(domainDependsOn, + "ibm_cis."+resourceName) + + g.Resources = append(g.Resources, g.loadDomains(crn, *z.ID, domainDependsOn)) + zoneResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + domainDependsOn = append(domainDependsOn, + "ibm_cis_domain."+zoneResourceName) + + // DNS Record + zoneID := *z.ID + dnsOpts := &dnsrecordsv1.DnsRecordsV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + // Domain Setting + g.Resources = append(g.Resources, g.loadDomainSettings(crn, *z.ID, domainDependsOn)) + + // DNS Records + dnsService, err := dnsrecordsv1.NewDnsRecordsV1(dnsOpts) + if err != nil { + return err + } + + dOpts := &dnsrecordsv1.ListAllDnsRecordsOptions{} + dnsList, _, err := dnsService.ListAllDnsRecords(dOpts) + if err != nil { + return err + } + + // IBM Network CIS WAF Package + cisWAFPackagesOpt := &wafrulepackagesapiv1.WafRulePackagesApiV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneID: &zoneID, + } + cisWAFPackageClient, _ := wafrulepackagesapiv1.NewWafRulePackagesApiV1(cisWAFPackagesOpt) + wasPkgList, _, err := cisWAFPackageClient.ListWafPackages(&wafrulepackagesapiv1.ListWafPackagesOptions{}) + if err != nil { + return err + } + + for _, wafPkg := range wasPkgList.Result { + cisWAFPackageOpt := &wafrulepackagesapiv1.GetWafPackageOptions{ + PackageID: wafPkg.ID, + } + wafPkg, _, err := cisWAFPackageClient.GetWafPackage(cisWAFPackageOpt) + if err != nil { + return err + } + + if wafPkg.Result != nil && wafPkg.Result.ActionMode != nil { + g.Resources = append(g.Resources, g.loadWafRulePackage(crn, *z.ID, *wafPkg.Result.ID, *wafPkg.Result.ActionMode, *wafPkg.Result.Sensitivity, domainDependsOn)) + + // CIS waf-groups + cisWAFGroupOpt := &wafrulegroupsapiv1.WafRuleGroupsApiV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneID: &zoneID, + } + cisWAFGroupClient, _ := wafrulegroupsapiv1.NewWafRuleGroupsApiV1(cisWAFGroupOpt) + wasGrpList, _, err := cisWAFGroupClient.ListWafRuleGroups(&wafrulegroupsapiv1.ListWafRuleGroupsOptions{ + PkgID: wafPkg.Result.ID, + }) + if err != nil { + return err + } + for _, wafGrp := range wasGrpList.Result { + g.Resources = append(g.Resources, g.loadWafGroups(crn, *z.ID, *wafPkg.Result.ID, *wafGrp.ID, domainDependsOn)) + } + } + } + + // Rate Limit + rateLimitPoolOpts := &zoneratelimitsv1.ZoneRateLimitsV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{BearerToken: bluemixToken}, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + rateLimitService, _ := zoneratelimitsv1.NewZoneRateLimitsV1(rateLimitPoolOpts) + rateLimitList, _, err := rateLimitService.ListAllZoneRateLimits(&zoneratelimitsv1.ListAllZoneRateLimitsOptions{}) + if err != nil { + return err + } + + for _, rl := range rateLimitList.Result { + g.Resources = append(g.Resources, g.loadRateLimit(crn, *z.ID, *rl.ID, domainDependsOn)) + } + + // Firewall - Lockdown + firewallOpts := &zonelockdownv1.ZoneLockdownV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + fService, err := zonelockdownv1.NewZoneLockdownV1(firewallOpts) + if err != nil { + return err + } + + firewallList, _, err := fService.ListAllZoneLockownRules(&zonelockdownv1.ListAllZoneLockownRulesOptions{}) + if err != nil { + return err + } + + for _, f := range firewallList.Result { + g.Resources = append(g.Resources, g.loadFirewall(crn, *z.ID, *f.ID, "lockdowns", domainDependsOn)) + } + + // Firewall - AccessRules + firewallAccessOpts := &zonefirewallaccessrulesv1.ZoneFirewallAccessRulesV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + fAccessService, err := zonefirewallaccessrulesv1.NewZoneFirewallAccessRulesV1(firewallAccessOpts) + if err != nil { + return err + } + + firewalAccesslList, _, err := fAccessService.ListAllZoneAccessRules(&zonefirewallaccessrulesv1.ListAllZoneAccessRulesOptions{}) + if err != nil { + return err + } + + for _, f := range firewalAccesslList.Result { + if f.Configuration.Target != nil { + g.Resources = append(g.Resources, g.loadFirewall(crn, *z.ID, *f.ID, "access_rules", domainDependsOn)) + } + } + + // Useragent blocking rules + firewallUAOpts := &useragentblockingrulesv1.UserAgentBlockingRulesV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + fUAService, err := useragentblockingrulesv1.NewUserAgentBlockingRulesV1(firewallUAOpts) + if err != nil { + return err + } + + firewalUAlList, _, err := fUAService.ListAllZoneUserAgentRules(&useragentblockingrulesv1.ListAllZoneUserAgentRulesOptions{}) + if err != nil { + return err + } + + for _, f := range firewalUAlList.Result { + if f.Configuration.Target != nil { + g.Resources = append(g.Resources, g.loadFirewall(crn, *z.ID, *f.ID, "ua_rules", domainDependsOn)) + } + } + + // IBM Network CIS Edge Function Action & Triggers + cisEdgeFunctionOpt := &edgefunctionsapiv1.EdgeFunctionsApiV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + cisEdgeFunctionClient, _ := edgefunctionsapiv1.NewEdgeFunctionsApiV1(cisEdgeFunctionOpt) + edgeActionResonse, _, err := cisEdgeFunctionClient.ListEdgeFunctionsActions(&edgefunctionsapiv1.ListEdgeFunctionsActionsOptions{}) + if err != nil { + return err + } + + for _, el := range edgeActionResonse.Result { + if el.Routes != nil { + for _, elT := range el.Routes { + g.Resources = append(g.Resources, g.loadEdgeFunctionAction(crn, *z.ID, *elT.Script, domainDependsOn)) + elResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + edgeFunctionActionDependsOn := makeDependsOn(domainDependsOn, + "ibm_cis_edge_functions_action."+elResourceName) + + g.Resources = append(g.Resources, g.loadEdgeFunctionTrigger(crn, *z.ID, *elT.ID, edgeFunctionActionDependsOn)) + } + } + } + + // Range app + rangeAppOpt := &rangeapplicationsv1.RangeApplicationsV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + rangeAppClient, _ := rangeapplicationsv1.NewRangeApplicationsV1(rangeAppOpt) + ranegAppList, _, err := rangeAppClient.ListRangeApps(&rangeapplicationsv1.ListRangeAppsOptions{}) + if err != nil { + return err + } + + for _, r := range ranegAppList.Result { + g.Resources = append(g.Resources, g.loadRangeApp(crn, *z.ID, *r.ID, domainDependsOn)) + } + + // Page Rules + pageRueleOpt := &pageruleapiv1.PageRuleApiV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneID: &zoneID, + } + + pageRuleClient, _ := pageruleapiv1.NewPageRuleApiV1(pageRueleOpt) + pageRuleList, _, err := pageRuleClient.ListPageRules(&pageruleapiv1.ListPageRulesOptions{}) + if err != nil { + return err + } + + for _, p := range pageRuleList.Result { + g.Resources = append(g.Resources, g.loadPageRule(crn, *z.ID, *p.ID, domainDependsOn)) + } + + // Custom Page + customPageOpt := &custompagesv1.CustomPagesV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + customPageClient, _ := custompagesv1.NewCustomPagesV1(customPageOpt) + customPageList, _, err := customPageClient.ListInstanceCustomPages(&custompagesv1.ListInstanceCustomPagesOptions{}) + if err != nil { + return err + } + + for _, cp := range customPageList.Result { + if cp.URL != nil { + g.Resources = append(g.Resources, g.loadCustomPage(crn, *z.ID, *cp.ID, *cp.URL, domainDependsOn)) + } + } + + // SSL Certificate - order + sslOpt := &sslcertificateapiv1.SslCertificateApiV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + sslClient, err := sslcertificateapiv1.NewSslCertificateApiV1(sslOpt) + if err != nil { + return err + } + sslList, _, err := sslClient.ListCertificates(&sslcertificateapiv1.ListCertificatesOptions{}) + if err != nil { + return err + } + for _, cert := range sslList.Result { + g.Resources = append(g.Resources, g.loadSSLCertificates(crn, *z.ID, *cert.ID, domainDependsOn)) + } + + // routingv1 + routingOpt := &routingv1.RoutingV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + routingClient, err := routingv1.NewRoutingV1(routingOpt) + if err != nil { + return err + } + routingList, _, err := routingClient.GetSmartRouting(&routingv1.GetSmartRoutingOptions{}) + if err != nil { + return err + } + if routingList != nil { + g.Resources = append(g.Resources, g.loadCISRouting(crn, *z.ID, domainDependsOn)) + } + + // Filters + filterOpts := &filtersv1.FiltersV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + } + + filterClient, err := filtersv1.NewFiltersV1(filterOpts) + if err != nil { + return err + } + + filterList, _, err := filterClient.ListAllFilters(&filtersv1.ListAllFiltersOptions{ + Crn: &crn, + ZoneIdentifier: &zoneID, + XAuthUserToken: &bluemixToken, + }) + if err != nil { + return err + } + + if filterList != nil { + for _, f := range filterList.Result { + g.Resources = append(g.Resources, g.loadFilters(crn, *z.ID, *f.ID, domainDependsOn)) + } + } + + // Cache Settings + g.Resources = append(g.Resources, g.loadCacheSettings(crn, *z.ID, domainDependsOn)) + + // TLS Settings + g.Resources = append(g.Resources, g.loadTLSSettings(crn, *z.ID, domainDependsOn)) + + for _, d := range dnsList.Result { + g.Resources = append(g.Resources, g.loadDNSRecords(crn, *z.ID, *d.ID, domainDependsOn)) + dnsResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dnsDependsOn := makeDependsOn(domainDependsOn, + "ibm_cis_dns_record."+dnsResourceName) + + // Global Load Balancer + gblSetttingOpts := &globalloadbalancerv1.GlobalLoadBalancerV1Options{ + URL: DefaultCisURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + Crn: &crn, + ZoneIdentifier: &zoneID, + } + + gblService, err := globalloadbalancerv1.NewGlobalLoadBalancerV1(gblSetttingOpts) + if err != nil { + return err + } + + gblList, _, err := gblService.ListAllLoadBalancers(&globalloadbalancerv1.ListAllLoadBalancersOptions{}) + if err != nil { + return err + } + + for _, gb := range gblList.Result { + g.Resources = append(g.Resources, g.loadGlobalBalancer(crn, *z.ID, *gb.ID, dnsDependsOn)) + } + } + } + } + + return nil +} + +func makeDependsOn(dependsOn []string, resource string) []string { + return append(dependsOn, resource) +} diff --git a/providers/ibm/cloud_functions.go b/providers/ibm/cloud_functions.go new file mode 100644 index 000000000..a613a0f2b --- /dev/null +++ b/providers/ibm/cloud_functions.go @@ -0,0 +1,240 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "net/http" + "net/url" + "os" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + + ns "github.com/IBM-Cloud/bluemix-go/api/functions" + "github.com/IBM-Cloud/bluemix-go/session" + + "github.com/apache/openwhisk-client-go/whisk" +) + +// CloudFunctionGenerator .. +type CloudFunctionGenerator struct { + IBMService +} + +func (g CloudFunctionGenerator) loadPackages(namespace, pkgName string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", namespace, pkgName), + pkgName, + "ibm_function_package", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + return resource +} + +func (g CloudFunctionGenerator) loadRules(namespace, ruleName string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", namespace, ruleName), + normalizeResourceName(ruleName, false), + "ibm_function_rule", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + return resource +} + +func (g CloudFunctionGenerator) loadTriggers(namespace, triggerName string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s:%s", namespace, triggerName), + normalizeResourceName(triggerName, false), + "ibm_function_trigger", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + return resource +} + +/* + * + * Configure a HTTP client using the OpenWhisk properties (i.e. host, auth, iamtoken) + * Only cf-based namespaces needs auth key value. + * iam-based namespace don't have an auth key and needs only iam token for authorization. + * + */ +func setupOpenWhiskClientConfigIAM(response ns.NamespaceResponse, c *bluemix.Config, region string) (*whisk.Client, error) { + u, _ := url.Parse(fmt.Sprintf("https://%s.functions.cloud.ibm.com/api", region)) + wskClient, _ := whisk.NewClient(http.DefaultClient, &whisk.Config{ + Host: u.Host, + Version: "v1", + }) + + if os.Getenv("TF_LOG") != "" { + whisk.SetDebug(true) + } + + // Configure whisk properties to handle iam-based/iam-migrated namespaces. + if response.IsIamEnabled() { + additionalHeaders := make(http.Header) + additionalHeaders.Add("Authorization", c.IAMAccessToken) + additionalHeaders.Add("X-Namespace-Id", response.GetID()) + + wskClient.Config.Namespace = response.GetID() + wskClient.Config.AdditionalHeaders = additionalHeaders + return wskClient, nil + } + + return nil, fmt.Errorf("Failed to create whisk config object for IAM based namespace '%v'", response.GetName()) +} + +// InitResources .. +func (g *CloudFunctionGenerator) InitResources() error { + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + + bmxConfig.Region = region + + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + err = authenticateAPIKey(sess) + if err != nil { + return err + } + + err = authenticateCF(sess) + if err != nil { + return err + } + + nsClient, err := ns.New(sess) + if err != nil { + return err + } + + nsList, err := nsClient.Namespaces().GetNamespaces() + if err != nil { + return nil + } + + for _, n := range nsList.Namespaces { + // Namespace + if !n.IsIamEnabled() { + continue + } + + // Build whisk object + wskClient, err := setupOpenWhiskClientConfigIAM(n, sess.Config, region) + if err != nil { + return err + } + + // Package + packageService := wskClient.Packages + pkgOptions := &whisk.PackageListOptions{ + Limit: 100, + Skip: 0, + } + pkgs, _, err := packageService.List(pkgOptions) + if err != nil { + return fmt.Errorf("Error retrieving IBM Cloud Function package: %s", err) + } + + for _, p := range pkgs { + g.Resources = append(g.Resources, g.loadPackages(n.GetName(), p.GetName())) + } + + // Action + actionService := wskClient.Actions + actionOptions := &whisk.ActionListOptions{ + Limit: 100, + Skip: 0, + } + actions, _, err := actionService.List("", actionOptions) + if err != nil { + return fmt.Errorf("Error retrieving IBM Cloud Function action: %s", err) + } + + for _, a := range actions { + actionID := "" + parts := strings.Split(a.Namespace, "/") + if len(parts) == 2 { + var pkgDependsOn []string + pkgDependsOn = append(pkgDependsOn, + "ibm_function_package."+terraformutils.TfSanitize(parts[1])) + actionID = fmt.Sprintf("%s/%s", parts[1], a.Name) + g.Resources = append(g.Resources, terraformutils.NewResource( + fmt.Sprintf("%s:%s", n.GetName(), actionID), + normalizeResourceName(a.Name, false), + "ibm_function_action", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": pkgDependsOn, + })) + } else { + g.Resources = append(g.Resources, terraformutils.NewResource( + fmt.Sprintf("%s:%s", n.GetName(), a.Name), + normalizeResourceName(a.Name, false), + "ibm_function_action", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{})) + } + } + + // Rule + ruleService := wskClient.Rules + ruleOptions := &whisk.RuleListOptions{ + Limit: 100, + Skip: 0, + } + rules, _, err := ruleService.List(ruleOptions) + if err != nil { + return fmt.Errorf("Error retrieving IBM Cloud Function rule: %s", err) + } + + for _, r := range rules { + g.Resources = append(g.Resources, g.loadRules(n.GetName(), r.Name)) + } + + // Triggers + triggerService := wskClient.Triggers + triggerOptions := &whisk.TriggerListOptions{ + Limit: 100, + Skip: 0, + } + triggers, _, err := triggerService.List(triggerOptions) + if err != nil { + return fmt.Errorf("Error retrieving IBM Cloud Function trigger: %s", err) + } + + for _, t := range triggers { + g.Resources = append(g.Resources, g.loadTriggers(n.GetName(), t.Name)) + } + } + + return nil +} diff --git a/providers/ibm/container_cluster.go b/providers/ibm/container_cluster.go new file mode 100644 index 000000000..652437ffe --- /dev/null +++ b/providers/ibm/container_cluster.go @@ -0,0 +1,122 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" + "github.com/IBM-Cloud/bluemix-go/session" +) + +type ContainerClusterGenerator struct { + IBMService +} + +func (g ContainerClusterGenerator) loadcluster(clustersID, clusterName string) terraformutils.Resource { + resource := terraformutils.NewResource( + clustersID, + normalizeResourceName(clusterName, false), + "ibm_container_cluster", + "ibm", + map[string]string{ + "force_delete_storage": "true", + "update_all_workers": "false", + "wait_for_worker_update": "true", + }, + []string{}, + map[string]interface{}{}) + + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^worker_num$", "^region$", + ) + return resource +} + +func (g ContainerClusterGenerator) loadWorkerPools(clustersID, poolID, poolName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", clustersID, poolID), + normalizeResourceName(poolName, true), + "ibm_container_worker_pool", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g ContainerClusterGenerator) loadWorkerPoolZones(clustersID, poolID, zoneID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", clustersID, poolID, zoneID), + normalizeResourceName("ibm_container_worker_pool_zone_attachment", true), + "ibm_container_worker_pool_zone_attachment", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g *ContainerClusterGenerator) InitResources() error { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + client, err := containerv1.New(sess) + if err != nil { + return err + } + + clusters, err := client.Clusters().List(containerv1.ClusterTargetHeader{}) + if err != nil { + return err + } + + for _, cs := range clusters { + g.Resources = append(g.Resources, g.loadcluster(cs.ID, cs.Name)) + clusterResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + workerPools, err := client.WorkerPools().ListWorkerPools(cs.ID, containerv1.ClusterTargetHeader{ + ResourceGroup: cs.ResourceGroupID, + }) + if err != nil { + return err + } + for _, pool := range workerPools { + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_container_cluster."+clusterResourceName) + g.Resources = append(g.Resources, g.loadWorkerPools(cs.ID, pool.ID, pool.Name, dependsOn)) + poolResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + + dependsOn = append(dependsOn, + "ibm_container_worker_pool."+poolResourceName) + zones := pool.Zones + for _, zone := range zones { + g.Resources = append(g.Resources, g.loadWorkerPoolZones(cs.ID, pool.ID, zone.ID, dependsOn)) + } + } + } + return nil +} diff --git a/providers/ibm/cos.go b/providers/ibm/cos.go new file mode 100644 index 000000000..62c105a86 --- /dev/null +++ b/providers/ibm/cos.go @@ -0,0 +1,128 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "regexp" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + + ibmaws "github.com/IBM/ibm-cos-sdk-go/aws" + cossession "github.com/IBM/ibm-cos-sdk-go/aws/session" + coss3 "github.com/IBM/ibm-cos-sdk-go/service/s3" +) + +type COSGenerator struct { + IBMService +} + +func (g COSGenerator) loadCOS(cosID string, cosName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + cosID, + normalizeResourceName(cosName, false), + "ibm_resource_instance", + "ibm", + []string{}) + return resources +} + +func (g COSGenerator) loadCOSBuckets(bucketID, bucketName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + bucketID, + normalizeResourceName(bucketName, false), + "ibm_cos_bucket", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g *COSGenerator) InitResources() error { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("cloud-object-storage", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + cosInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + authEndpoint := "https://iam.cloud.ibm.com/identity/token" + for _, cs := range cosInstances { + g.Resources = append(g.Resources, g.loadCOS(cs.ID, cs.Name)) + csResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + s3Conf := ibmaws.NewConfig().WithCredentials(ibmiam.NewStaticCredentials(ibmaws.NewConfig(), authEndpoint, os.Getenv("IC_API_KEY"), cs.ID)).WithS3ForcePathStyle(true).WithEndpoint("s3.us-south.cloud-object-storage.appdomain.cloud") + s3Sess := cossession.Must(cossession.NewSession()) + s3Client := coss3.New(s3Sess, s3Conf) + singleSiteLocationRegex := regexp.MustCompile("^[a-z]{3}[0-9][0-9]-[a-z]{4,8}$") + regionLocationRegex := regexp.MustCompile("^[a-z]{2}-[a-z]{2,5}-[a-z]{4,8}$") + crossRegionLocationRegex := regexp.MustCompile("^[a-z]{2}-[a-z]{4,8}$") + d, _ := s3Client.ListBucketsExtended(&coss3.ListBucketsExtendedInput{}) + for _, b := range d.Buckets { + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_resource_instance."+csResourceName) + var apiType, location string + bLocationConstraint := *b.LocationConstraint + if singleSiteLocationRegex.MatchString(bLocationConstraint) { + apiType = "ss1" + location = strings.Split(bLocationConstraint, "-")[0] + } + if regionLocationRegex.MatchString(bLocationConstraint) { + apiType = "rl" + location = fmt.Sprintf("%s-%s", strings.Split(bLocationConstraint, "-")[0], strings.Split(bLocationConstraint, "-")[1]) + } + if crossRegionLocationRegex.MatchString(bLocationConstraint) { + apiType = "crl" + location = strings.Split(bLocationConstraint, "-")[0] + } + bucketID := fmt.Sprintf("%s:%s:%s:meta:%s:%s", strings.ReplaceAll(cs.ID, "::", ""), "bucket", *b.Name, apiType, location) + g.Resources = append(g.Resources, g.loadCOSBuckets(bucketID, *b.Name, dependsOn)) + } + } + + return nil +} diff --git a/providers/ibm/database_elasticsearch.go b/providers/ibm/database_elasticsearch.go new file mode 100644 index 000000000..458fa439b --- /dev/null +++ b/providers/ibm/database_elasticsearch.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabaseElasticSearchGenerator ... +type DatabaseElasticSearchGenerator struct { + IBMService +} + +// loadElasticSearchDB ... +func (g DatabaseElasticSearchGenerator) loadElasticSearchDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabaseElasticSearchGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-elasticsearch", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + elasticSearchInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + for _, db := range elasticSearchInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadElasticSearchDB(db.ID, db.Name)) + } + } + + return nil +} diff --git a/providers/ibm/database_etcd.go b/providers/ibm/database_etcd.go new file mode 100644 index 000000000..5eb32ace1 --- /dev/null +++ b/providers/ibm/database_etcd.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabaseETCDGenerator ... +type DatabaseETCDGenerator struct { + IBMService +} + +// loadETCDDB ... +func (g DatabaseETCDGenerator) loadETCDDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabaseETCDGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-etcd", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + etcdInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + for _, db := range etcdInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadETCDDB(db.ID, db.Name)) + } + } + + return nil +} diff --git a/providers/ibm/database_mongo.go b/providers/ibm/database_mongo.go new file mode 100644 index 000000000..d91c4d299 --- /dev/null +++ b/providers/ibm/database_mongo.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabaseMongoGenerator ... +type DatabaseMongoGenerator struct { + IBMService +} + +// loadMongoDB ... +func (g DatabaseMongoGenerator) loadMongoDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabaseMongoGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-mongodb", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + mongoInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + for _, db := range mongoInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadMongoDB(db.ID, db.Name)) + } + } + + return nil +} diff --git a/providers/ibm/database_postgresql.go b/providers/ibm/database_postgresql.go new file mode 100644 index 000000000..515953716 --- /dev/null +++ b/providers/ibm/database_postgresql.go @@ -0,0 +1,85 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabasePostgresqlGenerator ... +type DatabasePostgresqlGenerator struct { + IBMService +} + +// loadPostgresqlDB ... +func (g DatabasePostgresqlGenerator) loadPostgresqlDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabasePostgresqlGenerator) InitResources() error { + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-postgresql", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + postgreSQLInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + + for _, db := range postgreSQLInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadPostgresqlDB(db.ID, db.Name)) + } + + } + + return nil +} diff --git a/providers/ibm/database_rabbitmq.go b/providers/ibm/database_rabbitmq.go new file mode 100644 index 000000000..14cf2dedf --- /dev/null +++ b/providers/ibm/database_rabbitmq.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabaseRabbitMQGenerator ... +type DatabaseRabbitMQGenerator struct { + IBMService +} + +// loadRabbitMQDB ... +func (g DatabaseRabbitMQGenerator) loadRabbitMQDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabaseRabbitMQGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-rabbitmq", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + rabbitmqInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + for _, db := range rabbitmqInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadRabbitMQDB(db.ID, db.Name)) + } + } + + return nil +} diff --git a/providers/ibm/database_redis.go b/providers/ibm/database_redis.go new file mode 100644 index 000000000..9d15b1f48 --- /dev/null +++ b/providers/ibm/database_redis.go @@ -0,0 +1,85 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +// DatabaseRedisGenerator ... +type DatabaseRedisGenerator struct { + IBMService +} + +// loadRedisDB ... +func (g DatabaseRedisGenerator) loadRedisDB(dbID string, dbName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + dbID, + normalizeResourceName(dbName, false), + "ibm_database", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *DatabaseRedisGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("databases-for-redis", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + redisInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + + for _, db := range redisInstances { + if db.RegionID == region { + g.Resources = append(g.Resources, g.loadRedisDB(db.ID, db.Name)) + } + } + + return nil +} diff --git a/providers/ibm/helpers.go b/providers/ibm/helpers.go new file mode 100644 index 000000000..fd5a6a63c --- /dev/null +++ b/providers/ibm/helpers.go @@ -0,0 +1,39 @@ +package ibm + +import ( + "fmt" + "math/rand" + "regexp" + "strings" +) + +func normalizeResourceName(s string, rand bool) string { + specialChars := `-<>()*#{}[]|@_ .%'",&` + for _, c := range specialChars { + s = strings.ReplaceAll(s, string(c), "_") + } + s = regexp.MustCompile(`^[^a-zA-Z_]+`).ReplaceAllLiteralString(s, "") + s = strings.TrimSuffix(s, "`_") + if rand { + randString := RandStringBytes(4) + return fmt.Sprintf("%s_%s", strings.ToLower(s), randString) + } + return strings.ToLower(s) +} + +const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789" + +func RandStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} +func getRandom(names map[string]struct{}, name string, random bool) (map[string]struct{}, bool) { + if _, ok := names[name]; ok { + random = true + } + names[name] = struct{}{} + return names, random +} diff --git a/providers/ibm/iam.go b/providers/ibm/iam.go new file mode 100644 index 000000000..46e7bd814 --- /dev/null +++ b/providers/ibm/iam.go @@ -0,0 +1,376 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/iampap/iampapv1" + "github.com/IBM-Cloud/bluemix-go/api/iamuum/iamuumv2" + "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM/go-sdk-core/core" + "github.com/IBM/platform-services-go-sdk/iamidentityv1" + "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" +) + +type IAMGenerator struct { + IBMService +} + +func (g IAMGenerator) loadUserPolicies(policyID string, user string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + fmt.Sprintf("%s/%s", user, policyID), + normalizeResourceName("iam_user_policy", true), + "ibm_iam_user_policy", + "ibm", + []string{}) + return resources +} + +func (g IAMGenerator) loadAccessGroups() func(grpID, grpName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(grpID, grpName string) terraformutils.Resource { + names, random = getRandom(names, grpName, random) + resources := terraformutils.NewSimpleResource( + grpID, + normalizeResourceName(grpName, random), + "ibm_iam_access_group", + "ibm", + []string{}) + return resources + } +} + +func (g IAMGenerator) loadServiceIDs() func(serviceID, grpName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(grpID, grpName string) terraformutils.Resource { + names, random = getRandom(names, grpName, random) + resources := terraformutils.NewSimpleResource( + grpID, + normalizeResourceName(grpName, random), + "ibm_iam_service_id", + "ibm", + []string{}) + return resources + } +} + +func (g IAMGenerator) loadAuthPolicies(policyID string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + policyID, + normalizeResourceName("iam_authorization_policy", true), + "ibm_iam_authorization_policy", + "ibm", + []string{}) + return resources +} + +func (g IAMGenerator) loadCustomRoles() func(roleID, roleName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(roleID, roleName string) terraformutils.Resource { + names, random = getRandom(names, roleName, random) + resources := terraformutils.NewSimpleResource( + roleID, + normalizeResourceName(roleName, random), + "ibm_iam_custom_role", + "ibm", + []string{}) + return resources + } +} + +func (g IAMGenerator) loadServicePolicies(serviceID, policyID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", serviceID, policyID), + normalizeResourceName("iam_service_policy", true), + "ibm_iam_service_policy", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g IAMGenerator) loadAccessGroupMembers() func(grpID string, dependsOn []string, grpName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(grpID string, dependsOn []string, grpName string) terraformutils.Resource { + names, random = getRandom(names, grpName, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", grpID, grpID), + normalizeResourceName(grpName, random), + "ibm_iam_access_group_members", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +func (g IAMGenerator) loadAccessGroupPolicies(grpID, policyID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", grpID, policyID), + normalizeResourceName("iam_access_group_policy", true), + "ibm_iam_access_group_policy", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g IAMGenerator) loadAccessGroupDynamicPolicies() func(grpID, ruleID, name string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(grpID, ruleID, name string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, name, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", grpID, ruleID), + normalizeResourceName(name, random), + "ibm_iam_access_group_dynamic_rule", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +func (g *IAMGenerator) InitResources() error { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + userManagementAPI, err := usermanagementv2.New(sess) + if err != nil { + return err + } + err = authenticateAPIKey(sess) + if err != nil { + return err + } + generation := envFallBack([]string{"Generation"}, "2") + gen, err := strconv.Atoi(generation) + if err != nil { + return err + } + userInfo, err := fetchUserDetails(sess, gen) + if err != nil { + return err + } + accountID := userInfo.userAccount + + users, err := userManagementAPI.UserInvite().GetUsers(userInfo.userAccount) + if err != nil { + return err + } + iampap, err := iampapv1.New(sess) + if err != nil { + return err + } + + for _, u := range users.Resources { + // User policies + policies, err := iampap.V1Policy().List(iampapv1.SearchParams{ + AccountID: accountID, + IAMID: u.IamID, + Type: iampapv1.AccessPolicyType, + }) + if err != nil { + return err + } + for _, p := range policies { + g.Resources = append(g.Resources, g.loadUserPolicies(p.ID, u.Email)) + } + } + + iamuumClient, err := iamuumv2.New(sess) + if err != nil { + return err + } + + agrps, err := iamuumClient.AccessGroup().List(accountID) + if err != nil { + return err + } + fnObjt := g.loadAccessGroups() + agmfnObj := g.loadAccessGroupMembers() + for _, group := range agrps { + g.Resources = append(g.Resources, fnObjt(group.ID, group.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_iam_access_group."+resourceName) + g.Resources = append(g.Resources, agmfnObj(group.ID, dependsOn, group.Name)) + + policies, err := iampap.V1Policy().List(iampapv1.SearchParams{ + AccountID: accountID, + AccessGroupID: group.ID, + Type: iampapv1.AccessPolicyType, + }) + if err != nil { + return fmt.Errorf("error retrieving access group policy: %s", err) + } + for _, p := range policies { + g.Resources = append(g.Resources, g.loadAccessGroupPolicies(group.ID, p.ID, dependsOn)) + } + + dynamicPolicies, err := iamuumClient.DynamicRule().List(group.ID) + if err != nil { + return err + } + dpfnObj := g.loadAccessGroupDynamicPolicies() + for _, d := range dynamicPolicies { + g.Resources = append(g.Resources, dpfnObj(group.ID, d.RuleID, d.Name, dependsOn)) + } + } + + // service id and service policy + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + iamIDurl := "https://iam.cloud.ibm.com" + iamOptions := &iamidentityv1.IamIdentityV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamIDurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + + iamPolicyOptions := &iampolicymanagementv1.IamPolicyManagementV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamIDurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + + iamIDClient, err := iamidentityv1.NewIamIdentityV1(iamOptions) + if err != nil { + return err + } + + iamPolicyClient, err := iampolicymanagementv1.NewIamPolicyManagementV1(iamPolicyOptions) + if err != nil { + return err + } + + start := "" + allrecs := []iamidentityv1.ServiceID{} + var pg int64 = 100 + + for { + listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ + AccountID: &accountID, + Pagesize: &pg, + } + if start != "" { + listServiceIDOptions.Pagetoken = &start + } + + serviceIDs, resp, err := iamIDClient.ListServiceIds(&listServiceIDOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) + } + start = GetNextIAM(serviceIDs.Next) + allrecs = append(allrecs, serviceIDs.Serviceids...) + if start == "" { + break + } + } + servicefnObjt := g.loadServiceIDs() + // loop through all service IDs and fetch policies correspponds to each service ID + for _, service := range allrecs { + g.Resources = append(g.Resources, servicefnObjt(*service.ID, *service.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_iam_service_id."+resourceName) + + listServicePolicyOptions := iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(accountID), + IamID: core.StringPtr(*service.IamID), + Type: core.StringPtr("access"), + } + + policyList, _, err := iamPolicyClient.ListPolicies(&listServicePolicyOptions) + policies := policyList.Policies + + if err != nil { + return fmt.Errorf("error retrieving service policy: %s", err) + } + + for _, p := range policies { + g.Resources = append(g.Resources, g.loadServicePolicies(*service.ID, *p.ID, dependsOn)) + } + } + + // Authorization policy + listAuthPolicyOptions := iampolicymanagementv1.ListPoliciesOptions{ + AccountID: core.StringPtr(accountID), + Type: core.StringPtr("authorization"), + } + + authPolicyList, _, err := iamPolicyClient.ListPolicies(&listAuthPolicyOptions) + authPolicies := authPolicyList.Policies + + if err != nil { + return fmt.Errorf("error retrieving authorization policy: %s", err) + } + + for _, ap := range authPolicies { + g.Resources = append(g.Resources, g.loadAuthPolicies(*ap.ID)) + } + + // Custom role + listCustomRoleOptions := iampolicymanagementv1.ListRolesOptions{ + AccountID: core.StringPtr(accountID), + } + + rolesList, _, err := iamPolicyClient.ListRoles(&listCustomRoleOptions) + customRoles := rolesList.CustomRoles + + if err != nil { + return fmt.Errorf("error retrieving custom roles: %s", err) + } + rolefnObjt := g.loadCustomRoles() + for _, r := range customRoles { + g.Resources = append(g.Resources, rolefnObjt(*r.ID, *r.Name)) + } + + return nil +} diff --git a/providers/ibm/ibm_certificate_manager.go b/providers/ibm/ibm_certificate_manager.go new file mode 100644 index 000000000..4e496b884 --- /dev/null +++ b/providers/ibm/ibm_certificate_manager.go @@ -0,0 +1,174 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/certificatemanager" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +type CMGenerator struct { + IBMService +} + +func (g CMGenerator) loadCM(cmID, cmGuID string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + cmID, + cmGuID, + "ibm_resource_instance", + "ibm", + []string{}) + return resources +} + +func (g CMGenerator) loadImportedCM(cmID, certificateID, cisInstance string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + cmID, + certificateID, + "ibm_certificate_manager_import", + "ibm", + map[string]string{ + "dns_provider_instance_crn": cisInstance, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g CMGenerator) loadOrderedCM(cmID, certificateID, cisInstance string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + cmID, + certificateID, + "ibm_certificate_manager_order", + "ibm", + map[string]string{ + "dns_provider_instance_crn": cisInstance, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g *CMGenerator) InitResources() error { + + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + var cisInstance string + var cisID string + cis := g.Args["cis"] + if cis != nil { + cisInstance = cis.(string) + } + + // Client creation + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + certManagementClient, err := certificatemanager.New(sess) + if err != nil { + return err + } + + // Get ServiceID of certificate manager service + serviceID, err := catalogClient.ResourceCatalog().FindByName("cloudcerts", true) + if err != nil { + return err + } + + serviceID2, err := catalogClient.ResourceCatalog().FindByName("internet-svcs", true) + if err != nil { + return err + } + + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + + query2 := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID2[0].ID, + } + + // Get all Certificate manager instances + cmInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + + // Get all CIS instances + cisInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query2) + if err != nil { + return err + } + for _, cis := range cisInstances { + if cisInstance == cis.Name { + cisID = cis.Guid + } + } + + // Get all certificates associated with a certificate manager instance + for _, cmInstance := range cmInstances { + + g.Resources = append(g.Resources, g.loadCM(cmInstance.ID, cmInstance.Guid)) + + // For each instance get associated certificates + certificateList, err := certManagementClient.Certificate().ListCertificates(cmInstance.ID) + if err != nil { + return err + } + + for _, cert := range certificateList { + // Get certificate info + certificatedata, err := certManagementClient.Certificate().GetCertData(cert.ID) + if err != nil { + return err + } + + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_resource_instance."+terraformutils.TfSanitize(cmInstance.Guid)) + + if certificatedata.Imported { + g.Resources = append(g.Resources, g.loadImportedCM(cert.ID, cert.ID, cisID, dependsOn)) + } else { + g.Resources = append(g.Resources, g.loadOrderedCM(cert.ID, cert.ID, cisID, dependsOn)) + } + } + } + + return nil +} diff --git a/providers/ibm/ibm_dl.go b/providers/ibm/ibm_dl.go new file mode 100644 index 000000000..eb01e8f1d --- /dev/null +++ b/providers/ibm/ibm_dl.go @@ -0,0 +1,143 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + dlProviderV2 "github.com/IBM/networking-go-sdk/directlinkproviderv2" + dl "github.com/IBM/networking-go-sdk/directlinkv1" +) + +// DLGenerator ... +type DLGenerator struct { + IBMService +} + +func (g DLGenerator) createDirectLinkGatewayResources(gatewayID, gatewayName string) terraformutils.Resource { + resource := terraformutils.NewSimpleResource( + gatewayID, + normalizeResourceName(gatewayName, false), + "ibm_dl_gateway", + "ibm", + []string{}) + return resource +} + +func (g DLGenerator) createDirectLinkVirtualConnectionResources(gatewayID, connectionID, connectionName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s", gatewayID, connectionID), + normalizeResourceName(connectionName, false), + "ibm_dl_virtual_connection", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g DLGenerator) createDirectLinkProviderGatewayResources(providerGatewayID, providerGatewayName string) terraformutils.Resource { + resource := terraformutils.NewSimpleResource( + providerGatewayID, + normalizeResourceName(providerGatewayName, false), + "ibm_dl_provider_gateway", + "ibm", + []string{}) + return resource +} + +// InitResources ... +func (g *DLGenerator) InitResources() error { + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + dlURL := "https://directlink.cloud.ibm.com/v1" + directlinkOptions := &dl.DirectLinkV1Options{ + URL: envFallBack([]string{"IBMCLOUD_DL_API_ENDPOINT"}, dlURL), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + Version: CreateVersionDate(), + } + dlclient, err := dl.NewDirectLinkV1(directlinkOptions) + if err != nil { + return err + } + + listGatewaysOptions := &dl.ListGatewaysOptions{} + gateways, response, err := dlclient.ListGateways(listGatewaysOptions) + if err != nil { + return fmt.Errorf("Error Fetching Direct Link Gateways %s\n%s", err, response) + } + if gateways.Gateways != nil { + for _, gateway := range gateways.Gateways { + g.Resources = append(g.Resources, g.createDirectLinkGatewayResources(*gateway.ID, *gateway.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var dependsOn []string + dependsOn = append(dependsOn, "ibm_dl_gateway."+resourceName) + listGatewayVirtualConnectionsOptions := &dl.ListGatewayVirtualConnectionsOptions{ + GatewayID: gateway.ID, + } + connections, response, err := dlclient.ListGatewayVirtualConnections(listGatewayVirtualConnectionsOptions) + if err != nil { + return fmt.Errorf("Error Fetching Direct Link Virtual connections %s\n%s", err, response) + } + for _, connection := range connections.VirtualConnections { + g.Resources = append(g.Resources, g.createDirectLinkVirtualConnectionResources(*gateway.ID, *connection.ID, *connection.Name, dependsOn)) + } + } + } + + dlproviderURL := "https://directlink.cloud.ibm.com/provider/v2" + dlproviderOptions := &dlProviderV2.DirectLinkProviderV2Options{ + URL: envFallBack([]string{"IBMCLOUD_DL_PROVIDER_API_ENDPOINT"}, dlproviderURL), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + Version: CreateVersionDate(), + } + dlproviderclient, err := dlProviderV2.NewDirectLinkProviderV2(dlproviderOptions) + if err != nil { + return err + } + start := "" + allrecs := []dlProviderV2.ProviderGateway{} + for { + listProviderGatewaysOptions := &dlProviderV2.ListProviderGatewaysOptions{} + if start != "" { + listProviderGatewaysOptions.Start = &start + } + + providerGateways, resp, err := dlproviderclient.ListProviderGateways(listProviderGatewaysOptions) + if err != nil { + return fmt.Errorf("Error Listing Direct Link Provider Gateways %s\n%s", err, resp) + } + start = GetNext(providerGateways.Next) + allrecs = append(allrecs, providerGateways.Gateways...) + if start == "" { + break + } + } + for _, providerGateway := range allrecs { + g.Resources = append(g.Resources, g.createDirectLinkProviderGatewayResources(*providerGateway.ID, *providerGateway.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_floating_ip.go b/providers/ibm/ibm_is_floating_ip.go new file mode 100644 index 000000000..2d487e385 --- /dev/null +++ b/providers/ibm/ibm_is_floating_ip.go @@ -0,0 +1,97 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// FloatingIPGenerator ... +type FloatingIPGenerator struct { + IBMService +} + +func (g FloatingIPGenerator) createFloatingIPResources(fipID, fipName string) terraformutils.Resource { + resource := terraformutils.NewResource( + fipID, + normalizeResourceName(fipName, false), + "ibm_is_floating_ip", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + + // Conflict parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^zone$", + ) + return resource +} + +// InitResources ... +func (g *FloatingIPGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.FloatingIP + for { + options := &vpcv1.ListFloatingIpsOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + fips, response, err := vpcclient.ListFloatingIps(options) + if err != nil { + return fmt.Errorf("Error Fetching Floating IPs %s\n%s", err, response) + } + start = GetNext(fips.Next) + allrecs = append(allrecs, fips.FloatingIps...) + if start == "" { + break + } + } + + for _, fip := range allrecs { + g.Resources = append(g.Resources, g.createFloatingIPResources(*fip.ID, *fip.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_flow_log.go b/providers/ibm/ibm_is_flow_log.go new file mode 100644 index 000000000..7cc14a8c2 --- /dev/null +++ b/providers/ibm/ibm_is_flow_log.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// FlowLogGenerator ... +type FlowLogGenerator struct { + IBMService +} + +func (g FlowLogGenerator) createFlowLogResources(flogID, flogName string) terraformutils.Resource { + resource := terraformutils.NewSimpleResource( + flogID, + normalizeResourceName(flogName, false), + "ibm_is_flow_log", + "ibm", + []string{}) + return resource +} + +// InitResources ... +func (g *FlowLogGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.FlowLogCollector + for { + options := &vpcv1.ListFlowLogCollectorsOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + flogs, response, err := vpcclient.ListFlowLogCollectors(options) + if err != nil { + return fmt.Errorf("Error Fetching Flow Logs %s\n%s", err, response) + } + start = GetNext(flogs.Next) + allrecs = append(allrecs, flogs.FlowLogCollectors...) + if start == "" { + break + } + } + + for _, flog := range allrecs { + g.Resources = append(g.Resources, g.createFlowLogResources(*flog.ID, *flog.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_ike_policy.go b/providers/ibm/ibm_is_ike_policy.go new file mode 100644 index 000000000..524c7e7a8 --- /dev/null +++ b/providers/ibm/ibm_is_ike_policy.go @@ -0,0 +1,83 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// IkeGenerator ... +type IkeGenerator struct { + IBMService +} + +func (g IkeGenerator) createIkeResources(ikeID, ikeName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + ikeID, + normalizeResourceName(ikeName, false), + "ibm_is_ike_policy", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *IkeGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.IkePolicy + for { + options := &vpcv1.ListIkePoliciesOptions{} + if start != "" { + options.Start = &start + } + policies, response, err := vpcclient.ListIkePolicies(options) + if err != nil { + return fmt.Errorf("Error Fetching IKE Policies %s\n%s", err, response) + } + start = GetNext(policies.Next) + allrecs = append(allrecs, policies.IkePolicies...) + if start == "" { + break + } + } + + for _, policy := range allrecs { + g.Resources = append(g.Resources, g.createIkeResources(*policy.ID, *policy.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_image.go b/providers/ibm/ibm_is_image.go new file mode 100644 index 000000000..529283607 --- /dev/null +++ b/providers/ibm/ibm_is_image.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// ImageGenerator ... +type ImageGenerator struct { + IBMService +} + +func (g ImageGenerator) createImageResources(imageID, imageName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + imageID, + normalizeResourceName(imageName, true), + "ibm_is_image", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *ImageGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.Image + for { + options := &vpcv1.ListImagesOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + images, response, err := vpcclient.ListImages(options) + if err != nil { + return fmt.Errorf("Error Fetching Images %s\n%s", err, response) + } + start = GetNext(images.Next) + allrecs = append(allrecs, images.Images...) + if start == "" { + break + } + } + + for _, image := range allrecs { + g.Resources = append(g.Resources, g.createImageResources(*image.ID, *image.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_instance.go b/providers/ibm/ibm_is_instance.go new file mode 100644 index 000000000..8c0334500 --- /dev/null +++ b/providers/ibm/ibm_is_instance.go @@ -0,0 +1,100 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// InstanceGenerator ... +type InstanceGenerator struct { + IBMService +} + +func (g InstanceGenerator) createInstanceResources(instanceID, instanceName, instanceImgID string) terraformutils.Resource { + resource := terraformutils.NewResource( + instanceID, + normalizeResourceName(instanceName, false), + "ibm_is_instance", + "ibm", + map[string]string{ + "image": instanceImgID, + }, + []string{}, + map[string]interface{}{ + "keys": []string{}, + }) + + // Deprecated parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^port$", + ) + return resource +} + +// InitResources ... +func (g *InstanceGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.Instance + for { + options := &vpcv1.ListInstancesOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + instances, response, err := vpcclient.ListInstances(options) + if err != nil { + return fmt.Errorf("Error Fetching Instances %s\n%s", err, response) + } + start = GetNext(instances.Next) + allrecs = append(allrecs, instances.Instances...) + if start == "" { + break + } + } + + for _, instance := range allrecs { + g.Resources = append(g.Resources, g.createInstanceResources(*instance.ID, *instance.Name, *instance.Image.ID)) + } + return nil +} diff --git a/providers/ibm/ibm_is_instance_template.go b/providers/ibm/ibm_is_instance_template.go new file mode 100644 index 000000000..b79a062be --- /dev/null +++ b/providers/ibm/ibm_is_instance_template.go @@ -0,0 +1,71 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// InstanceTemplateGenerator ... +type InstanceTemplateGenerator struct { + IBMService +} + +func (g InstanceTemplateGenerator) createInstanceTemplateResources(templateID, templateName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + templateID, + normalizeResourceName(templateName, false), + "ibm_is_instance_template", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *InstanceTemplateGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + options := &vpcv1.ListInstanceTemplatesOptions{} + templates, response, err := vpcclient.ListInstanceTemplates(options) + if err != nil { + return fmt.Errorf("Error Fetching Instance Templates %s\n%s", err, response) + } + + for _, template := range templates.Templates { + instemp := template.(*vpcv1.InstanceTemplate) + g.Resources = append(g.Resources, g.createInstanceTemplateResources(*instemp.ID, *instemp.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_ipsec_policy.go b/providers/ibm/ibm_is_ipsec_policy.go new file mode 100644 index 000000000..5a561bac8 --- /dev/null +++ b/providers/ibm/ibm_is_ipsec_policy.go @@ -0,0 +1,89 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// IpsecGenerator ... +type IpsecGenerator struct { + IBMService +} + +func (g IpsecGenerator) createIpsecResources() func(ipsecID, ipsecName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(ipsecID, ipsecName string) terraformutils.Resource { + names, random = getRandom(names, ipsecName, random) + resources := terraformutils.NewSimpleResource( + ipsecID, + normalizeResourceName(ipsecName, random), + "ibm_is_ipsec_policy", + "ibm", + []string{}) + return resources + } +} + +// InitResources ... +func (g *IpsecGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.IPsecPolicy + for { + options := &vpcv1.ListIpsecPoliciesOptions{} + if start != "" { + options.Start = &start + } + policies, response, err := vpcclient.ListIpsecPolicies(options) + if err != nil { + return fmt.Errorf("Error Fetching IPSEC Policies %s\n%s", err, response) + } + start = GetNext(policies.Next) + allrecs = append(allrecs, policies.IpsecPolicies...) + if start == "" { + break + } + } + + fnObjt := g.createIpsecResources() + for _, policy := range allrecs { + g.Resources = append(g.Resources, fnObjt(*policy.ID, *policy.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_lb.go b/providers/ibm/ibm_is_lb.go new file mode 100644 index 000000000..7f53b49e0 --- /dev/null +++ b/providers/ibm/ibm_is_lb.go @@ -0,0 +1,224 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// LBGenerator ... +type LBGenerator struct { + IBMService +} + +func (g LBGenerator) createLBResources(lbID, lbName string) terraformutils.Resource { + resource := terraformutils.NewResource( + lbID, + normalizeResourceName(lbName, true), + "ibm_is_lb", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + + // Deprecated parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^profile$", + ) + return resource +} + +func (g LBGenerator) createLBPoolResources(lbID, lbPoolID, lbPoolName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", lbID, lbPoolID), + normalizeResourceName(lbPoolName, true), + "ibm_is_lb_pool", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g LBGenerator) createLBPoolMemberResources(lbID, lbPoolID, lbPoolMemberID, lbPoolMemberName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", lbID, lbPoolID, lbPoolMemberID), + normalizeResourceName(lbPoolMemberName, true), + "ibm_is_lb_pool_member", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g LBGenerator) createLBListenerResources(lbID, lbListenerID, lbListenerName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", lbID, lbListenerID), + normalizeResourceName(lbListenerName, true), + "ibm_is_lb_listener", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g LBGenerator) createLBListenerPolicyResources(lbID, lbListenerID, lbListenerPolicyID, lbListenerPolicyName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", lbID, lbListenerID, lbListenerPolicyID), + normalizeResourceName(lbListenerPolicyName, true), + "ibm_is_lb_listener_policy", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g LBGenerator) createLBListenerPolicyRuleResources(lbID, lbListenerID, lbListenerPolicyID, lbListenerPolicyRuleID, lbListenerPolicyName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s/%s", lbID, lbListenerID, lbListenerPolicyID, lbListenerPolicyRuleID), + normalizeResourceName(lbListenerPolicyName, true), + "ibm_is_lb_listener_policy_rule", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// InitResources ... +func (g *LBGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + rg := g.Args["resource_group"] + if rg != nil { + _ = rg.(string) + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + var allrecs []vpcv1.LoadBalancer + + listLoadBalancersOptions := &vpcv1.ListLoadBalancersOptions{} + lbs, response, err := vpcclient.ListLoadBalancers(listLoadBalancersOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpcs %s\n%s", err, response) + } + allrecs = append(allrecs, lbs.LoadBalancers...) + + for _, lb := range allrecs { + var dependsOn []string + g.Resources = append(g.Resources, g.createLBResources(*lb.ID, *lb.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn = append(dependsOn, + "ibm_is_lb."+resourceName) + listLoadBalancerPoolsOptions := &vpcv1.ListLoadBalancerPoolsOptions{ + LoadBalancerID: lb.ID, + } + lbPools, response, err := vpcclient.ListLoadBalancerPools(listLoadBalancerPoolsOptions) + if err != nil { + return fmt.Errorf("Error Fetching Load Balancer Pools %s\n%s", err, response) + } + for _, lbPool := range lbPools.Pools { + g.Resources = append(g.Resources, g.createLBPoolResources(*lb.ID, *lbPool.ID, *lbPool.Name, dependsOn)) + lbPoolResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn1 := makeDependsOn(dependsOn, + "ibm_is_lb_pool."+lbPoolResourceName) + listLoadBalancerPoolMembersOptions := &vpcv1.ListLoadBalancerPoolMembersOptions{ + LoadBalancerID: lb.ID, + PoolID: lbPool.ID, + } + lbPoolMembers, response, err := vpcclient.ListLoadBalancerPoolMembers(listLoadBalancerPoolMembersOptions) + if err != nil { + return fmt.Errorf("Error Fetching Load Balancer Pool Members %s\n%s", err, response) + } + for _, lbPoolMember := range lbPoolMembers.Members { + g.Resources = append(g.Resources, g.createLBPoolMemberResources(*lb.ID, *lbPool.ID, *lbPoolMember.ID, *lbPool.Name, dependsOn1)) + } + } + + listLoadBalancerListenersOptions := &vpcv1.ListLoadBalancerListenersOptions{ + LoadBalancerID: lb.ID, + } + lbListeners, response, err := vpcclient.ListLoadBalancerListeners(listLoadBalancerListenersOptions) + if err != nil { + return fmt.Errorf("Error Fetching Load Balancer Listeners %s\n%s", err, response) + } + for _, lbListener := range lbListeners.Listeners { + g.Resources = append(g.Resources, g.createLBListenerResources(*lb.ID, *lbListener.ID, *lbListener.ID, dependsOn)) + lbListenerResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var dependsOn2 = append(dependsOn, //nolint:goimports,gofmt + "ibm_is_lb_listener."+lbListenerResourceName) + listLoadBalancerListenerPoliciesOptions := &vpcv1.ListLoadBalancerListenerPoliciesOptions{ + LoadBalancerID: lb.ID, + ListenerID: lbListener.ID, + } + lbListenerPolicies, response, err := vpcclient.ListLoadBalancerListenerPolicies(listLoadBalancerListenerPoliciesOptions) + if err != nil { + return fmt.Errorf("Error Fetching Load Balancer Listener Policies %s\n%s", err, response) + } + for _, lbListenerPolicy := range lbListenerPolicies.Policies { + g.Resources = append(g.Resources, g.createLBListenerPolicyResources(*lb.ID, *lbListener.ID, *lbListenerPolicy.ID, *lbListenerPolicy.Name, dependsOn2)) + lbListenerPolicyResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn2 = append(dependsOn2, + "ibm_is_lb_listener_policy."+lbListenerPolicyResourceName) + listLoadBalancerListenerPolicyRulesOptions := &vpcv1.ListLoadBalancerListenerPolicyRulesOptions{ + LoadBalancerID: lb.ID, + ListenerID: lbListener.ID, + PolicyID: lbListenerPolicy.ID, + } + lbListenerPolicyRules, response, err := vpcclient.ListLoadBalancerListenerPolicyRules(listLoadBalancerListenerPolicyRulesOptions) + if err != nil { + return fmt.Errorf("Error Fetching Load Balancer Listener Policy Rules %s\n%s", err, response) + } + for _, lbListenerPolicyRule := range lbListenerPolicyRules.Rules { + g.Resources = append(g.Resources, g.createLBListenerPolicyRuleResources(*lb.ID, *lbListener.ID, *lbListenerPolicy.ID, *lbListenerPolicyRule.ID, *lbListenerPolicyRule.ID, dependsOn2)) + + } + } + } + } + return nil +} diff --git a/providers/ibm/ibm_is_network_acl.go b/providers/ibm/ibm_is_network_acl.go new file mode 100644 index 000000000..cb2912789 --- /dev/null +++ b/providers/ibm/ibm_is_network_acl.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// NetworkACLGenerator ... +type NetworkACLGenerator struct { + IBMService +} + +func (g NetworkACLGenerator) createNetworkACLResources(nwaclID, nwaclName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + nwaclID, + normalizeResourceName(nwaclName, true), + "ibm_is_network_acl", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *NetworkACLGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.NetworkACL + for { + options := &vpcv1.ListNetworkAclsOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + nwacls, response, err := vpcclient.ListNetworkAcls(options) + if err != nil { + return fmt.Errorf("Error Fetching Network ACLs %s\n%s", err, response) + } + start = GetNext(nwacls.Next) + allrecs = append(allrecs, nwacls.NetworkAcls...) + if start == "" { + break + } + } + + for _, nwacl := range allrecs { + g.Resources = append(g.Resources, g.createNetworkACLResources(*nwacl.ID, *nwacl.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_public_gateway.go b/providers/ibm/ibm_is_public_gateway.go new file mode 100644 index 000000000..0cdff6948 --- /dev/null +++ b/providers/ibm/ibm_is_public_gateway.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// PublicGatewayGenerator ... +type PublicGatewayGenerator struct { + IBMService +} + +func (g PublicGatewayGenerator) createPublicGatewayResources(publicGatewayID, publicGatewayName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + publicGatewayID, + normalizeResourceName(publicGatewayName, false), + "ibm_is_public_gateway", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *PublicGatewayGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.PublicGateway + for { + options := &vpcv1.ListPublicGatewaysOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + pgs, response, err := vpcclient.ListPublicGateways(options) + if err != nil { + return fmt.Errorf("Error Fetching Public Gateways %s\n%s", err, response) + } + start = GetNext(pgs.Next) + allrecs = append(allrecs, pgs.PublicGateways...) + if start == "" { + break + } + } + + for _, pg := range allrecs { + g.Resources = append(g.Resources, g.createPublicGatewayResources(*pg.ID, *pg.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_security_group.go b/providers/ibm/ibm_is_security_group.go new file mode 100644 index 000000000..3925bd56b --- /dev/null +++ b/providers/ibm/ibm_is_security_group.go @@ -0,0 +1,137 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "reflect" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// SecurityGroupGenerator ... +type SecurityGroupGenerator struct { + IBMService +} + +func (g SecurityGroupGenerator) createSecurityGroupResources(sgID, sgName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + sgID, + normalizeResourceName(sgName, false), + "ibm_is_security_group", + "ibm", + []string{}) + return resources +} + +func (g SecurityGroupGenerator) createSecurityGroupRuleResources(sgID, sgRuleID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s.%s", sgID, sgRuleID), + normalizeResourceName("ibm_is_security_group_rule", true), + "ibm_is_security_group_rule", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// InitResources ... +func (g *SecurityGroupGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.SecurityGroup + for { + options := &vpcv1.ListSecurityGroupsOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + sgs, response, err := vpcclient.ListSecurityGroups(options) + if err != nil { + return fmt.Errorf("Error Fetching security Groups %s\n%s", err, response) + } + start = GetNext(sgs.Next) + allrecs = append(allrecs, sgs.SecurityGroups...) + if start == "" { + break + } + } + + for _, group := range allrecs { + var dependsOn []string + + g.Resources = append(g.Resources, g.createSecurityGroupResources(*group.ID, *group.Name)) + sgResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn = append(dependsOn, + "ibm_is_security_group."+sgResourceName) + listSecurityGroupRulesOptions := &vpcv1.ListSecurityGroupRulesOptions{ + SecurityGroupID: group.ID, + } + rules, response, err := vpcclient.ListSecurityGroupRules(listSecurityGroupRulesOptions) + if err != nil { + return fmt.Errorf("Error Fetching security group rules %s\n%s", err, response) + } + for _, sgrule := range rules.Rules { + switch reflect.TypeOf(sgrule).String() { + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) + g.Resources = append(g.Resources, g.createSecurityGroupRuleResources(*group.ID, *rule.ID, dependsOn)) + } + + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) + g.Resources = append(g.Resources, g.createSecurityGroupRuleResources(*group.ID, *rule.ID, dependsOn)) + } + + case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": + { + rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) + g.Resources = append(g.Resources, g.createSecurityGroupRuleResources(*group.ID, *rule.ID, dependsOn)) + } + } + } + } + return nil +} diff --git a/providers/ibm/ibm_is_ssh_key.go b/providers/ibm/ibm_is_ssh_key.go new file mode 100644 index 000000000..e2b7f6090 --- /dev/null +++ b/providers/ibm/ibm_is_ssh_key.go @@ -0,0 +1,78 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// SSHKeyGenerator ... +type SSHKeyGenerator struct { + IBMService +} + +func (g SSHKeyGenerator) createSSHKeyResources(sshKeyID, sshKeyName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + sshKeyID, + normalizeResourceName(sshKeyName, true), + "ibm_is_ssh_key", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *SSHKeyGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + options := &vpcv1.ListKeysOptions{} + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + keys, response, err := vpcclient.ListKeys(options) + if err != nil { + return fmt.Errorf("Error Fetching SSH Keys %s\n%s", err, response) + } + + for _, key := range keys.Keys { + g.Resources = append(g.Resources, g.createSSHKeyResources(*key.ID, *key.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_subnet.go b/providers/ibm/ibm_is_subnet.go new file mode 100644 index 000000000..a71dc2923 --- /dev/null +++ b/providers/ibm/ibm_is_subnet.go @@ -0,0 +1,96 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// SubnetGenerator ... +type SubnetGenerator struct { + IBMService +} + +func (g SubnetGenerator) createSubnetResources(subnetID, subnetName string) terraformutils.Resource { + resource := terraformutils.NewResource( + subnetID, + normalizeResourceName(subnetName, false), + "ibm_is_subnet", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^total_ipv4_address_count$", + ) + return resource +} + +// InitResources ... +func (g *SubnetGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + + start := "" + var allrecs []vpcv1.Subnet + for { + options := &vpcv1.ListSubnetsOptions{} + if start != "" { + options.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + options.ResourceGroupID = &rg + } + subnets, response, err := vpcclient.ListSubnets(options) + if err != nil { + return fmt.Errorf("Error Fetching subnets %s\n%s", err, response) + } + start = GetNext(subnets.Next) + allrecs = append(allrecs, subnets.Subnets...) + if start == "" { + break + } + } + + for _, subnet := range allrecs { + g.Resources = append(g.Resources, g.createSubnetResources(*subnet.ID, *subnet.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_virtual_endpoint_gateway.go b/providers/ibm/ibm_is_virtual_endpoint_gateway.go new file mode 100644 index 000000000..09cce57c8 --- /dev/null +++ b/providers/ibm/ibm_is_virtual_endpoint_gateway.go @@ -0,0 +1,127 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// VPEGenerator ... +type VPEGenerator struct { + IBMService +} + +func (g VPEGenerator) createVPEGatewayResources(gatewayID, gatewayName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + gatewayID, + normalizeResourceName(gatewayName, false), + "ibm_is_virtual_endpoint_gateway", + "ibm", + []string{}) + return resources +} + +func (g VPEGenerator) createVPEGatewayIPResources(gatewayID, gatewayIPID, gatewayIPName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", gatewayID, gatewayIPID), + normalizeResourceName(gatewayIPName, false), + "ibm_is_virtual_endpoint_gateway_ip", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// InitResources ... +func (g *VPEGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + + start := "" + allrecs := []vpcv1.EndpointGateway{} + for { + listEndpointGatewaysOptions := &vpcv1.ListEndpointGatewaysOptions{} + if start != "" { + listEndpointGatewaysOptions.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + listEndpointGatewaysOptions.ResourceGroupID = &rg + } + gateways, response, err := vpcclient.ListEndpointGateways(listEndpointGatewaysOptions) + if err != nil { + return fmt.Errorf("Error Fetching endpoint gateways %s\n%s", err, response) + } + start = GetNext(gateways.Next) + allrecs = append(allrecs, gateways.EndpointGateways...) + if start == "" { + break + } + } + + for _, gateway := range allrecs { + var dependsOn []string + start := "" + allrecs := []vpcv1.ReservedIP{} + dependsOn = append(dependsOn, + "ibm_is_virtual_endpoint_gateway."+terraformutils.TfSanitize(*gateway.Name)) + g.Resources = append(g.Resources, g.createVPEGatewayResources(*gateway.ID, *gateway.Name)) + listEndpointGatewayIpsOptions := &vpcv1.ListEndpointGatewayIpsOptions{ + EndpointGatewayID: gateway.ID, + } + if start != "" { + listEndpointGatewayIpsOptions.Start = &start + } + ips, response, err := vpcclient.ListEndpointGatewayIps(listEndpointGatewayIpsOptions) + if err != nil { + return fmt.Errorf("Error Fetching endpoint gateway ips %s\n%s", err, response) + } + start = GetNext(ips.Next) + allrecs = append(allrecs, ips.Ips...) + if start == "" { + break + } + for _, ip := range allrecs { + g.Resources = append(g.Resources, g.createVPEGatewayIPResources(*gateway.ID, *ip.ID, *ip.Name, dependsOn)) + } + } + return nil +} diff --git a/providers/ibm/ibm_is_volume.go b/providers/ibm/ibm_is_volume.go new file mode 100644 index 000000000..bc5145b64 --- /dev/null +++ b/providers/ibm/ibm_is_volume.go @@ -0,0 +1,83 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "log" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// VolumeGenerator ... +type VolumeGenerator struct { + IBMService +} + +func (g VolumeGenerator) createVolumeResources(volID, volName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + volID, + normalizeResourceName(volName, true), + "ibm_is_volume", + "ibm", + []string{}) + return resources +} + +// InitResources ... +func (g *VolumeGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + log.Fatal("No API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.Volume + for { + options := &vpcv1.ListVolumesOptions{} + if start != "" { + options.Start = &start + } + volumes, response, err := vpcclient.ListVolumes(options) + if err != nil { + return fmt.Errorf("Error Fetching Volumes %s\n%s", err, response) + } + start = GetNext(volumes.Next) + allrecs = append(allrecs, volumes.Volumes...) + if start == "" { + break + } + } + + for _, volume := range allrecs { + g.Resources = append(g.Resources, g.createVolumeResources(*volume.ID, *volume.Name)) + } + return nil +} diff --git a/providers/ibm/ibm_is_vpc.go b/providers/ibm/ibm_is_vpc.go new file mode 100644 index 000000000..01cbca931 --- /dev/null +++ b/providers/ibm/ibm_is_vpc.go @@ -0,0 +1,213 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// VPCGenerator ... +type VPCGenerator struct { + IBMService +} + +func (g VPCGenerator) createVPCResources(vpcID, vpcName string) terraformutils.Resource { + resource := terraformutils.NewResource( + vpcID, + normalizeResourceName(vpcName, false), + "ibm_is_vpc", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + + // Deprecated parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^default_network_acl$", + ) + + return resource +} + +func (g VPCGenerator) createVPCAddressPrefixResources(vpcID, addPrefixID, addPrefixName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s", vpcID, addPrefixID), + normalizeResourceName(addPrefixName, false), + "ibm_is_vpc_address_prefix", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + + return resource +} + +func (g VPCGenerator) createVPCRouteResources(vpcID, routeID, routeName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", vpcID, routeID), + normalizeResourceName(routeName, false), + "ibm_is_vpc_route", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g VPCGenerator) createVPCRouteTableResources(vpcID, routeTableID, routeTableName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", vpcID, routeTableID), + normalizeResourceName(routeTableName, false), + "ibm_is_vpc_routing_table", + "ibm", + map[string]string{ + "vpc": vpcID, + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g VPCGenerator) createVPCRouteTableRouteResources(vpcID, routeTableID, routeTableRouteID, routeTableRouteName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", vpcID, routeTableID, routeTableRouteID), + normalizeResourceName(routeTableRouteName, false), + "ibm_is_vpc_routing_table_route", + "ibm", + map[string]string{ + "vpc": vpcID, + "routing_table": routeTableID, + "action": "deliver", + }, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + + // Deprecated parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^action$", + ) + return resource +} + +// InitResources ... +func (g *VPCGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.VPC + for { + listVpcsOptions := &vpcv1.ListVpcsOptions{} + if start != "" { + listVpcsOptions.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + listVpcsOptions.ResourceGroupID = &rg + } + vpcs, response, err := vpcclient.ListVpcs(listVpcsOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpcs %s\n%s", err, response) + } + start = GetNext(vpcs.Next) + allrecs = append(allrecs, vpcs.Vpcs...) + if start == "" { + break + } + } + + for _, vpc := range allrecs { + var dependsOn []string + g.Resources = append(g.Resources, g.createVPCResources(*vpc.ID, *vpc.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn = append(dependsOn, "ibm_is_vpc."+resourceName) + listVPCAddressPrefixesOptions := &vpcv1.ListVPCAddressPrefixesOptions{ + VPCID: vpc.ID, + } + addprefixes, response, err := vpcclient.ListVPCAddressPrefixes(listVPCAddressPrefixesOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpc address prefixes %s\n%s", err, response) + } + for _, addprefix := range addprefixes.AddressPrefixes { + g.Resources = append(g.Resources, g.createVPCAddressPrefixResources(*vpc.ID, *addprefix.ID, *addprefix.Name, dependsOn)) + } + + listVPCRoutesOptions := &vpcv1.ListVPCRoutesOptions{ + VPCID: vpc.ID, + } + routes, response, err := vpcclient.ListVPCRoutes(listVPCRoutesOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpc routes %s\n%s", err, response) + } + for _, route := range routes.Routes { + g.Resources = append(g.Resources, g.createVPCRouteResources(*vpc.ID, *route.ID, *route.Name, dependsOn)) + } + + listVPCRoutingTablesOptions := &vpcv1.ListVPCRoutingTablesOptions{ + VPCID: vpc.ID, + } + tables, response, err := vpcclient.ListVPCRoutingTables(listVPCRoutingTablesOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpc routing tables %s\n%s", err, response) + } + for _, table := range tables.RoutingTables { + g.Resources = append(g.Resources, g.createVPCRouteTableResources(*vpc.ID, *table.ID, *table.Name, dependsOn)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn = append(dependsOn, "ibm_is_vpc_routing_table."+resourceName) + listVPCRoutingTableRoutesOptions := &vpcv1.ListVPCRoutingTableRoutesOptions{ + VPCID: vpc.ID, + RoutingTableID: table.ID, + } + tableroutes, response, err := vpcclient.ListVPCRoutingTableRoutes(listVPCRoutingTableRoutesOptions) + if err != nil { + return fmt.Errorf("Error Fetching vpc route table routes %s\n%s", err, response) + } + for _, tableroute := range tableroutes.Routes { + g.Resources = append(g.Resources, g.createVPCRouteTableRouteResources(*vpc.ID, *table.ID, *tableroute.ID, *tableroute.Name, dependsOn)) + } + } + } + return nil +} diff --git a/providers/ibm/ibm_is_vpn_gateway.go b/providers/ibm/ibm_is_vpn_gateway.go new file mode 100644 index 000000000..a95f007e9 --- /dev/null +++ b/providers/ibm/ibm_is_vpn_gateway.go @@ -0,0 +1,120 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// VPNGatewayGenerator ... +type VPNGatewayGenerator struct { + IBMService +} + +func (g VPNGatewayGenerator) createVPNGatewayResources(vpngwID, vpngwName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + vpngwID, + normalizeResourceName(vpngwName, false), + "ibm_is_vpn_gateway", + "ibm", + []string{}) + return resources +} + +func (g VPNGatewayGenerator) createVPNGatewayConnectionResources(vpngwID, vpngwConnectionID, vpngwConnectionName string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", vpngwID, vpngwConnectionID), + normalizeResourceName(vpngwConnectionName, false), + "ibm_is_vpn_gateway_connections", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// InitResources ... +func (g *VPNGatewayGenerator) InitResources() error { + region := g.Args["region"].(string) + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + vpcurl := fmt.Sprintf("https://%s.iaas.cloud.ibm.com/v1", region) + vpcoptions := &vpcv1.VpcV1Options{ + URL: envFallBack([]string{"IBMCLOUD_IS_API_ENDPOINT"}, vpcurl), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + } + vpcclient, err := vpcv1.NewVpcV1(vpcoptions) + if err != nil { + return err + } + start := "" + var allrecs []vpcv1.VPNGatewayIntf + for { + listVPNGatewaysOptions := &vpcv1.ListVPNGatewaysOptions{} + if start != "" { + listVPNGatewaysOptions.Start = &start + } + if rg := g.Args["resource_group"].(string); rg != "" { + rg, err = GetResourceGroupID(apiKey, rg, region) + if err != nil { + return fmt.Errorf("Error Fetching Resource Group Id %s", err) + } + listVPNGatewaysOptions.ResourceGroupID = &rg + } + vpngws, response, err := vpcclient.ListVPNGateways(listVPNGatewaysOptions) + if err != nil { + return fmt.Errorf("Error Fetching VPN Gateways %s\n%s", err, response) + } + start = GetNext(vpngws.Next) + allrecs = append(allrecs, vpngws.VPNGateways...) + if start == "" { + break + } + } + + for _, gw := range allrecs { + vpngw := gw.(*vpcv1.VPNGateway) + var dependsOn []string + + g.Resources = append(g.Resources, g.createVPNGatewayResources(*vpngw.ID, *vpngw.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + dependsOn = append(dependsOn, + "ibm_is_vpn_gateway."+resourceName) + listVPNGatewayConnectionsOptions := &vpcv1.ListVPNGatewayConnectionsOptions{ + VPNGatewayID: vpngw.ID, + } + vpngwConnections, response, err := vpcclient.ListVPNGatewayConnections(listVPNGatewayConnectionsOptions) + if err != nil { + return fmt.Errorf("Error Fetching VPN Gateway Connections %s\n%s", err, response) + } + for _, connection := range vpngwConnections.Connections { + vpngwConnection := connection.(*vpcv1.VPNGatewayConnection) + g.Resources = append(g.Resources, g.createVPNGatewayConnectionResources(*vpngw.ID, *vpngwConnection.ID, *vpngwConnection.Name, dependsOn)) + } + } + return nil +} diff --git a/providers/ibm/ibm_kp.go b/providers/ibm/ibm_kp.go new file mode 100644 index 000000000..2a319550f --- /dev/null +++ b/providers/ibm/ibm_kp.go @@ -0,0 +1,131 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "context" + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" + kp "github.com/IBM/keyprotect-go-client" +) + +type KPGenerator struct { + IBMService +} + +func (g KPGenerator) loadKP() func(kpID, kpName string) terraformutils.Resource { + names := make(map[string]struct{}) + random := true + return func(kpID, kpName string) terraformutils.Resource { + names, random = getRandom(names, kpName, random) + resource := terraformutils.NewSimpleResource( + kpID, + normalizeResourceName(kpName, random), + "ibm_resource_instance", + "ibm", + []string{}) + return resource + } +} + +func (g KPGenerator) loadkPKeys() func(kpKeyCRN, kpKeyName string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := true + return func(kpKeyCRN, kpKeyName string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, kpKeyName, random) + resource := terraformutils.NewResource( + kpKeyCRN, + normalizeResourceName(kpKeyName, random), + "ibm_kms_key", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource + } +} + +func (g *KPGenerator) InitResources() error { + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("kms", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + kpInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + kpurl := fmt.Sprintf("https://%s.kms.cloud.ibm.com", region) + options := kp.ClientConfig{ + BaseURL: envFallBack([]string{"IBMCLOUD_KP_API_ENDPOINT"}, kpurl), + APIKey: os.Getenv("IC_API_KEY"), + Verbose: kp.VerboseFailOnly, + } + + client, err := kp.New(options, kp.DefaultTransport()) + if err != nil { + return err + } + fnObjt := g.loadKP() + for _, kpInstance := range kpInstances { + g.Resources = append(g.Resources, fnObjt(kpInstance.ID, kpInstance.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + client.Config.InstanceID = kpInstance.Guid + + output, err := client.GetKeys(context.Background(), 100, 0) + if err != nil { + return err + } + fnObjt := g.loadkPKeys() + for _, key := range output.Keys { + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_resource_instance."+resourceName) + g.Resources = append(g.Resources, fnObjt(key.CRN, key.Name, dependsOn)) + } + + } + + return nil +} diff --git a/providers/ibm/ibm_private_dns.go b/providers/ibm/ibm_private_dns.go new file mode 100644 index 000000000..3debc4a56 --- /dev/null +++ b/providers/ibm/ibm_private_dns.go @@ -0,0 +1,323 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev1/catalog" + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/controllerv2" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM/go-sdk-core/v3/core" + dns "github.com/IBM/networking-go-sdk/dnssvcsv1" +) + +// privateDNSTemplateGenerator ... +type privateDNSTemplateGenerator struct { + IBMService +} + +// loadPrivateDNS ... +func (g privateDNSTemplateGenerator) loadPrivateDNS() func(pDNSID, pDNSName, resGrpID string) terraformutils.Resource { + names := make(map[string]struct{}) + random := true + return func(pDNSID, pDNSName, resGrpID string) terraformutils.Resource { + names, random = getRandom(names, pDNSName, random) + resource := terraformutils.NewResource( + pDNSID, + normalizeResourceName(pDNSName, random), + "ibm_resource_instance", + "ibm", + map[string]string{ + "resource_group_id": resGrpID, + }, + []string{}, + map[string]interface{}{}) + return resource + } +} + +// loadPrivateDNSZone ... +func (g privateDNSTemplateGenerator) loadPrivateDNSZone(pDNSGuid string, zoneID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", pDNSGuid, zoneID), + normalizeResourceName("ibm_dns_zone", true), + "ibm_dns_zone", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// loadPrivateDNSPermittedNetwork ... +func (g privateDNSTemplateGenerator) loadPrivateDNSPermittedNetwork(pDNSGuid string, zoneID string, permittedNetworkID string, dependsOn []string) terraformutils.Resource { + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", pDNSGuid, zoneID, permittedNetworkID), + normalizeResourceName("ibm_dns_permitted_network", true), + "ibm_dns_permitted_network", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +// loadPrivateDNSResourceRecord ... +func (g privateDNSTemplateGenerator) loadPrivateDNSResourceRecord() func(pDNSGuid, zoneID, recordID, recordName string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(pDNSGuid, zoneID, recordID, recordName string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, recordName, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", pDNSGuid, zoneID, recordID), + normalizeResourceName(recordName, random), + "ibm_dns_resource_record", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +// loadPrivateDNSGLBMonitor ... +func (g privateDNSTemplateGenerator) loadPrivateDNSGLBMonitor() func(pDNSGuid, monitorID, monitorName string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(pDNSGuid, monitorID, monitorName string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, monitorName, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", pDNSGuid, monitorID), + normalizeResourceName(monitorName, random), + "ibm_dns_glb_monitor", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +// loadPrivateDNSGLBPool ... +func (g privateDNSTemplateGenerator) loadPrivateDNSGLBPool() func(pDNSGuid, poolID, poolName string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(pDNSGuid, poolID, poolName string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, poolName, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", pDNSGuid, poolID), + normalizeResourceName(poolName, random), + "ibm_dns_glb_pool", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +// loadPrivateDNSGLB ... +func (g privateDNSTemplateGenerator) loadPrivateDNSGLB() func(pDNSGuid, zoneID, lbID, lbName string, dependsOn []string) terraformutils.Resource { + names := make(map[string]struct{}) + random := false + return func(pDNSGuid, zoneID, lbID, lbName string, dependsOn []string) terraformutils.Resource { + names, random = getRandom(names, lbName, random) + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", pDNSGuid, zoneID, lbID), + normalizeResourceName(lbName, random), + "ibm_dns_glb", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources + } +} + +// InitResources ... +func (g *privateDNSTemplateGenerator) InitResources() error { + + region := g.Args["region"].(string) + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + Region: region, + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + defaultDNSURL := "https://api.dns-svcs.cloud.ibm.com/v1" + + err = authenticateAPIKey(sess) + if err != nil { + return err + } + + bluemixToken := "" + if strings.HasPrefix(sess.Config.IAMAccessToken, "Bearer") { + bluemixToken = sess.Config.IAMAccessToken[7:len(sess.Config.IAMAccessToken)] + } else { + bluemixToken = sess.Config.IAMAccessToken + } + + catalogClient, err := catalog.New(sess) + if err != nil { + return err + } + + controllerClient, err := controllerv2.New(sess) + if err != nil { + return err + } + + serviceID, err := catalogClient.ResourceCatalog().FindByName("dns-svcs", true) + if err != nil { + return err + } + query := controllerv2.ServiceInstanceQuery{ + ServiceID: serviceID[0].ID, + } + pDNSInstances, err := controllerClient.ResourceServiceInstanceV2().ListInstances(query) + if err != nil { + return err + } + + for _, instance := range pDNSInstances { + instanceID := instance.ID + instanceGUID := instance.Guid + // Instance + fnObjt := g.loadPrivateDNS() + g.Resources = append(g.Resources, fnObjt(instanceID, instance.Name, instance.ResourceGroupID)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var pDNSDependsOn []string + pDNSDependsOn = append(pDNSDependsOn, + "ibm_resource_instance."+resourceName) + + // Zones + zoneOpts := &dns.DnsSvcsV1Options{ + URL: defaultDNSURL, + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + } + + zService, err := dns.NewDnsSvcsV1(zoneOpts) + if err != nil { + return err + } + zoneOpt := dns.ListDnszonesOptions{ + InstanceID: &instanceGUID, + } + zoneList, _, err := zService.ListDnszones(&zoneOpt) + if err != nil { + return fmt.Errorf("error Listing Zones %s", err) + } + for _, zone := range zoneList.Dnszones { + zoneID := *zone.ID + g.Resources = append(g.Resources, g.loadPrivateDNSZone(instanceGUID, zoneID, pDNSDependsOn)) + domainResourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + domainDependsOn := makeDependsOn(pDNSDependsOn, "ibm_dns_zone."+domainResourceName) + + // Permitted Network Records + permittedNetworkOpt := dns.ListPermittedNetworksOptions{ + InstanceID: &instanceGUID, + DnszoneID: &zoneID, + } + permittedNetworkList, _, err := zService.ListPermittedNetworks(&permittedNetworkOpt) + if err != nil { + return fmt.Errorf("error Listing Permitted Networks %s", err) + } + for _, permittedNetwork := range permittedNetworkList.PermittedNetworks { + permittedNetworkID := *permittedNetwork.ID + g.Resources = append(g.Resources, g.loadPrivateDNSPermittedNetwork(instanceGUID, zoneID, permittedNetworkID, domainDependsOn)) + } + + // Resource Records + dnsRecordOpt := dns.ListResourceRecordsOptions{ + InstanceID: &instanceGUID, + DnszoneID: &zoneID, + } + resourceRecordList, _, err := zService.ListResourceRecords(&dnsRecordOpt) + if err != nil { + return fmt.Errorf("error Listing Resource Records %s", err) + } + + pdnsFnObjt := g.loadPrivateDNSResourceRecord() + for _, record := range resourceRecordList.ResourceRecords { + g.Resources = append(g.Resources, pdnsFnObjt(instanceGUID, zoneID, *record.ID, *record.Name, domainDependsOn)) + } + + // GLB Records + glbOpt := dns.ListLoadBalancersOptions{ + InstanceID: &instanceGUID, + DnszoneID: &zoneID, + } + glbOptList, _, err := zService.ListLoadBalancers(&glbOpt) + if err != nil { + return fmt.Errorf("error Listing GLBs %s", err) + } + glbFntObj := g.loadPrivateDNSGLB() + for _, lb := range glbOptList.LoadBalancers { + g.Resources = append(g.Resources, glbFntObj(instanceGUID, zoneID, *lb.ID, *lb.Name, domainDependsOn)) + } + } + // Monitor Records + monitorOpt := dns.ListMonitorsOptions{ + InstanceID: &instanceGUID, + } + glbMonitorList, _, err := zService.ListMonitors(&monitorOpt) + if err != nil { + return fmt.Errorf("error Listing GLB Monitor %s", err) + } + + lbMonitorObjt := g.loadPrivateDNSGLBMonitor() + for _, monitor := range glbMonitorList.Monitors { + g.Resources = append(g.Resources, lbMonitorObjt(instanceGUID, *monitor.ID, *monitor.Name, pDNSDependsOn)) + } + + // Pool Records + glbPoolOpt := dns.ListPoolsOptions{ + InstanceID: &instanceGUID, + } + glbPoolOptList, _, err := zService.ListPools(&glbPoolOpt) + if err != nil { + return fmt.Errorf("error Listing GLB Pools %s", err) + } + dnsGlbfnObj := g.loadPrivateDNSGLBPool() + for _, pool := range glbPoolOptList.Pools { + g.Resources = append(g.Resources, dnsGlbfnObj(instanceGUID, *pool.ID, *pool.Name, pDNSDependsOn)) + } + + } + + return nil +} diff --git a/providers/ibm/ibm_provider.go b/providers/ibm/ibm_provider.go new file mode 100644 index 000000000..85f16c4b2 --- /dev/null +++ b/providers/ibm/ibm_provider.go @@ -0,0 +1,127 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +const DefaultRegion = "us-south" +const NoRegion = "" + +type IBMProvider struct { //nolint + terraformutils.Provider + ResourceGroup string + Region string + CIS string +} + +func (p *IBMProvider) Init(args []string) error { + p.ResourceGroup = args[0] + p.Region = args[1] + p.CIS = args[2] + + var err error + if p.Region != DefaultRegion && p.Region != NoRegion { + err = os.Setenv("IC_REGION", p.Region) + } else { + p.Region = DefaultRegion + err = os.Setenv("IC_REGION", DefaultRegion) + } + if err != nil { + return err + } + return nil +} + +func (p *IBMProvider) GetName() string { + return "ibm" +} + +func (p *IBMProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "ibm": map[string]interface{}{ + "region": p.Region, + }, + }, + } +} + +func (IBMProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p *IBMProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "ibm_kp": &KPGenerator{}, + "ibm_container_vpc_cluster": &VPCClusterGenerator{}, + "ibm_container_cluster": &ContainerClusterGenerator{}, + "ibm_cos": &COSGenerator{}, + "ibm_database_elasticsearch": &DatabaseElasticSearchGenerator{}, + "ibm_database_etcd": &DatabaseETCDGenerator{}, + "ibm_database_mongo": &DatabaseMongoGenerator{}, + "ibm_database_postgresql": &DatabasePostgresqlGenerator{}, + "ibm_database_rabbitmq": &DatabaseRabbitMQGenerator{}, + "ibm_database_redis": &DatabaseRedisGenerator{}, + "ibm_iam": &IAMGenerator{}, + "ibm_is_instance_group": &InstanceGroupGenerator{}, + "ibm_is_vpc": &VPCGenerator{}, + "ibm_is_subnet": &SubnetGenerator{}, + "ibm_is_instance": &InstanceGenerator{}, + "ibm_is_security_group": &SecurityGroupGenerator{}, + "ibm_cis": &CISGenerator{}, + "ibm_is_network_acl": &NetworkACLGenerator{}, + "ibm_is_public_gateway": &PublicGatewayGenerator{}, + "ibm_is_volume": &VolumeGenerator{}, + "ibm_is_vpn_gateway": &VPNGatewayGenerator{}, + "ibm_is_lb": &LBGenerator{}, + "ibm_is_ssh_key": &SSHKeyGenerator{}, + "ibm_is_floating_ip": &FloatingIPGenerator{}, + "ibm_is_image": &ImageGenerator{}, + "ibm_is_ipsec_policy": &IpsecGenerator{}, + "ibm_is_ike_policy": &IkeGenerator{}, + "ibm_is_flow_log": &FlowLogGenerator{}, + "ibm_is_instance_template": &InstanceTemplateGenerator{}, + "ibm_function": &CloudFunctionGenerator{}, + "ibm_private_dns": &privateDNSTemplateGenerator{}, + "ibm_certificate_manager": &CMGenerator{}, + "ibm_direct_link": &DLGenerator{}, + "ibm_transit_gateway": &TGGenerator{}, + "ibm_vpe_gateway": &VPEGenerator{}, + "ibm_satellite": &SatelliteGenerator{}, + } +} + +func (p *IBMProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New("IBM: " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + + p.Service.SetArgs(map[string]interface{}{ + "resource_group": p.ResourceGroup, + "region": p.Region, + "cis": p.CIS, + }) + return nil +} diff --git a/providers/ibm/ibm_service.go b/providers/ibm/ibm_service.go new file mode 100644 index 000000000..6b22f1fd5 --- /dev/null +++ b/providers/ibm/ibm_service.go @@ -0,0 +1,23 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type IBMService struct { //nolint + terraformutils.Service +} diff --git a/providers/ibm/ibm_tg.go b/providers/ibm/ibm_tg.go new file mode 100644 index 000000000..51eb8be99 --- /dev/null +++ b/providers/ibm/ibm_tg.go @@ -0,0 +1,117 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "time" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + tg "github.com/IBM/networking-go-sdk/transitgatewayapisv1" +) + +// TGGenerator ... +type TGGenerator struct { + IBMService +} + +func (g TGGenerator) createTransitGatewayResources(gatewayID, gatewayName string) terraformutils.Resource { + resource := terraformutils.NewSimpleResource( + gatewayID, + normalizeResourceName(gatewayName, false), + "ibm_tg_gateway", + "ibm", + []string{}) + return resource +} + +func (g TGGenerator) createTransitGatewayConnectionResources(gatewayID, connectionID, connectionName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s", gatewayID, connectionID), + normalizeResourceName(connectionName, false), + "ibm_tg_connection", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +// CreateVersionDate requires mandatory version attribute. Any date from 2019-12-13 up to the currentdate may be provided. Specify the current date to request the latest version. +func CreateVersionDate() *string { + version := time.Now().Format("2006-01-02") + return &version +} + +// InitResources ... +func (g *TGGenerator) InitResources() error { + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + tgURL := "https://transit.cloud.ibm.com/v1" + transitgatewayOptions := &tg.TransitGatewayApisV1Options{ + URL: envFallBack([]string{"IBMCLOUD_TG_API_ENDPOINT"}, tgURL), + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + Version: CreateVersionDate(), + } + + tgclient, err := tg.NewTransitGatewayApisV1(transitgatewayOptions) + if err != nil { + return err + } + start := "" + allrecs := []tg.TransitGateway{} + for { + listTransitGatewaysOptions := &tg.ListTransitGatewaysOptions{} + if start != "" { + listTransitGatewaysOptions.Start = &start + } + + gateways, resp, err := tgclient.ListTransitGateways(listTransitGatewaysOptions) + if err != nil { + return fmt.Errorf("Error Listing Transit Gateways %s\n%s", err, resp) + } + start = GetNext(gateways.Next) + allrecs = append(allrecs, gateways.TransitGateways...) + if start == "" { + break + } + } + for _, gateway := range allrecs { + g.Resources = append(g.Resources, g.createTransitGatewayResources(*gateway.ID, *gateway.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_tg_gateway."+resourceName) + listTransitGatewayConnectionsOptions := &tg.ListTransitGatewayConnectionsOptions{ + TransitGatewayID: gateway.ID, + } + connections, response, err := tgclient.ListTransitGatewayConnections(listTransitGatewayConnectionsOptions) + if err != nil { + return fmt.Errorf("Error Listing Transit Gateway connections %s\n%s", err, response) + } + for _, connection := range connections.Connections { + g.Resources = append(g.Resources, g.createTransitGatewayConnectionResources(*gateway.ID, *connection.ID, *connection.Name, dependsOn)) + } + } + return nil +} diff --git a/providers/ibm/instance_groups.go b/providers/ibm/instance_groups.go new file mode 100644 index 000000000..31045a2f7 --- /dev/null +++ b/providers/ibm/instance_groups.go @@ -0,0 +1,195 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "math/rand" + "os" + "sync" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM/go-sdk-core/v4/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +// InstanceGroupGenerator ... +type InstanceGroupGenerator struct { + IBMService + fatalErrors chan error +} + +func (g *InstanceGroupGenerator) loadInstanceGroup(instanceGroupID, instanceGroupName string) terraformutils.Resource { + resources := terraformutils.NewSimpleResource( + instanceGroupID, + instanceGroupName, + "ibm_is_instance_group", + "ibm", + []string{}) + return resources +} + +func (g *InstanceGroupGenerator) loadInstanceGroupManger(instanceGroupID, instanceGroupManagerID, managerName string, dependsOn []string) terraformutils.Resource { + if managerName == "" { + managerName = fmt.Sprintf("manager-%d-%d", rand.Intn(100), rand.Intn(50)) + } + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s", instanceGroupID, instanceGroupManagerID), + managerName, + "ibm_is_instance_group_manager", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g *InstanceGroupGenerator) loadInstanceGroupMangerPolicy(instanceGroupID, instanceGroupManagerID, policyID, policyName string, dependsOn []string) terraformutils.Resource { + if policyName == "" { + policyName = fmt.Sprintf("manager-%d-%d", rand.Intn(100), rand.Intn(50)) + } + resources := terraformutils.NewResource( + fmt.Sprintf("%s/%s/%s", instanceGroupID, instanceGroupManagerID, policyID), + policyName, + "ibm_is_instance_group_manager_policy", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resources +} + +func (g *InstanceGroupGenerator) handlePolicies(sess *vpcv1.VpcV1, instanceGroupID, instanceGroupManagerID string, policies, dependsOn []string, waitGroup *sync.WaitGroup) { + defer waitGroup.Done() + for _, instanceGroupManagerPolicyID := range policies { + getInstanceGroupManagerPolicyOptions := vpcv1.GetInstanceGroupManagerPolicyOptions{ + ID: &instanceGroupManagerPolicyID, + InstanceGroupID: &instanceGroupID, + InstanceGroupManagerID: &instanceGroupManagerID, + } + data, response, err := sess.GetInstanceGroupManagerPolicy(&getInstanceGroupManagerPolicyOptions) + if err != nil { + g.fatalErrors <- fmt.Errorf("Error Getting InstanceGroup Manager Policy: %s\n%s", err, response) + } + instanceGroupManagerPolicy := data.(*vpcv1.InstanceGroupManagerPolicy) + g.Resources = append(g.Resources, g.loadInstanceGroupMangerPolicy(instanceGroupID, + instanceGroupManagerID, + instanceGroupManagerPolicyID, + *instanceGroupManagerPolicy.Name, + dependsOn)) + } +} + +func (g *InstanceGroupGenerator) handleManagers(sess *vpcv1.VpcV1, instanceGroupID string, managers, dependsOn []string, waitGroup *sync.WaitGroup) { + defer waitGroup.Done() + var policiesWG sync.WaitGroup + for _, instanceGroupManagerID := range managers { + getInstanceGroupManagerOptions := vpcv1.GetInstanceGroupManagerOptions{ + ID: &instanceGroupManagerID, + InstanceGroupID: &instanceGroupID, + } + instanceGroupManager, response, err := sess.GetInstanceGroupManager(&getInstanceGroupManagerOptions) + if err != nil { + g.fatalErrors <- fmt.Errorf("Error Getting InstanceGroup Manager: %s\n%s", err, response) + } + g.Resources = append(g.Resources, g.loadInstanceGroupManger(instanceGroupID, instanceGroupManagerID, *instanceGroupManager.Name, dependsOn)) + + policies := make([]string, 0) + + for i := 0; i < len(instanceGroupManager.Policies); i++ { + policies = append(policies, *(instanceGroupManager.Policies[i].ID)) + } + policiesWG.Add(1) + dependsOn1 := makeDependsOn(dependsOn, + "ibm_is_instance_group_manger."+terraformutils.TfSanitize(*instanceGroupManager.Name)) + go g.handlePolicies(sess, instanceGroupID, instanceGroupManagerID, policies, dependsOn1, &policiesWG) + } + policiesWG.Wait() +} + +func (g *InstanceGroupGenerator) handleInstanceGroups(sess *vpcv1.VpcV1, waitGroup *sync.WaitGroup) { + // Support for pagination + defer waitGroup.Done() + start := "" + var allrecs []vpcv1.InstanceGroup + for { + listInstanceGroupOptions := vpcv1.ListInstanceGroupsOptions{} + if start != "" { + listInstanceGroupOptions.Start = &start + } + instanceGroupsCollection, response, err := sess.ListInstanceGroups(&listInstanceGroupOptions) + if err != nil { + g.fatalErrors <- fmt.Errorf("Error Fetching InstanceGroups %s\n%s", err, response) + } + start = GetNext(instanceGroupsCollection.Next) + allrecs = append(allrecs, instanceGroupsCollection.InstanceGroups...) + if start == "" { + break + } + } + + var managersWG sync.WaitGroup + + for _, instanceGroup := range allrecs { + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_is_instance_group."+terraformutils.TfSanitize(*instanceGroup.Name)) + instanceGoupID := *instanceGroup.ID + g.Resources = append(g.Resources, g.loadInstanceGroup(instanceGoupID, *instanceGroup.Name)) + managers := make([]string, 0) + for i := 0; i < len(instanceGroup.Managers); i++ { + managers = append(managers, *(instanceGroup.Managers[i].ID)) + } + managersWG.Add(1) + go g.handleManagers(sess, instanceGoupID, managers, dependsOn, &managersWG) + } + managersWG.Wait() +} + +// InitResources ... +func (g *InstanceGroupGenerator) InitResources() error { + apiKey := os.Getenv("IC_API_KEY") + if apiKey == "" { + return fmt.Errorf("no API key set") + } + + // Instantiate the service with an API key based IAM authenticator + sess, err := vpcv1.NewVpcV1(&vpcv1.VpcV1Options{ + Authenticator: &core.IamAuthenticator{ + ApiKey: apiKey, + }, + }) + if err != nil { + return err + } + + g.fatalErrors = make(chan error) + + var instanceGroupWG sync.WaitGroup + instanceGroupWG.Add(1) + go g.handleInstanceGroups(sess, &instanceGroupWG) + + select { //nolint + case err := <-g.fatalErrors: + close(g.fatalErrors) + return err + } + instanceGroupWG.Wait() //nolint:govet + return nil +} diff --git a/providers/ibm/satellite.go b/providers/ibm/satellite.go new file mode 100644 index 000000000..be0fbc0eb --- /dev/null +++ b/providers/ibm/satellite.go @@ -0,0 +1,141 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + + "github.com/IBM/go-sdk-core/v3/core" +) + +type SatelliteGenerator struct { + IBMService +} + +func (g SatelliteGenerator) loadLocations(locID, locName string) terraformutils.Resource { + resource := terraformutils.NewResource( + locID, + normalizeResourceName(locName, false), + "ibm_satellite_location", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{}) + + // Remove parameters + resource.IgnoreKeys = append(resource.IgnoreKeys, + "^labels$", + ) + + return resource +} + +func (g SatelliteGenerator) loadAssignHostControlPlane(locID, hostID string, labels []string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s", locID, hostID), + normalizeResourceName("ibm_satellite_host", true), + "ibm_satellite_host", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "labels": labels, + "depends_on": dependsOn, + }) + return resource +} + +func (g *SatelliteGenerator) InitResources() error { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + + err = authenticateAPIKey(sess) + if err != nil { + return err + } + + bluemixToken := "" + if strings.HasPrefix(sess.Config.IAMAccessToken, "Bearer") { + bluemixToken = sess.Config.IAMAccessToken[7:len(sess.Config.IAMAccessToken)] + } else { + bluemixToken = sess.Config.IAMAccessToken + } + + containerEndpoint := kubernetesserviceapiv1.DefaultServiceURL + kubernetesServiceV1Options := &kubernetesserviceapiv1.KubernetesServiceApiV1Options{ + URL: envFallBack([]string{"IBMCLOUD_SATELLITE_API_ENDPOINT"}, containerEndpoint), + Authenticator: &core.BearerTokenAuthenticator{ + BearerToken: bluemixToken, + }, + } + + satelliteClient, err := kubernetesserviceapiv1.NewKubernetesServiceApiV1(kubernetesServiceV1Options) + if err != nil { + return err + } + + getSatLocOpts := &kubernetesserviceapiv1.GetSatelliteLocationsOptions{} + locations, _, err := satelliteClient.GetSatelliteLocations(getSatLocOpts) + if err != nil { + return err + } + + for _, loc := range locations { + var locDependsOn []string + + // Location + if loc.Deployments != nil && !strings.Contains(*loc.Deployments.Message, "R0037") { + g.Resources = append(g.Resources, g.loadLocations(*loc.ID, *loc.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + locDependsOn = append(locDependsOn, + "ibm_satellite_location."+resourceName) + + // Assign Host - Control plane + getSatHostOpts := &kubernetesserviceapiv1.GetSatelliteHostsOptions{ + Controller: loc.ID, + } + hosts, resp, err := satelliteClient.GetSatelliteHosts(getSatHostOpts) + if err != nil { + return fmt.Errorf("Error getting satellite control plane hosts %s\n%s", err, resp) + } + + for _, host := range hosts { + if *host.Assignment.ClusterName == "infrastructure" { + hostLabels := []string{} + for key, value := range host.Labels { + hostLabels = append(hostLabels, fmt.Sprintf("%s=%s", key, value)) + } + g.Resources = append(g.Resources, g.loadAssignHostControlPlane(*loc.ID, *host.ID, hostLabels, locDependsOn)) + } + } + + } + } + + return nil +} diff --git a/providers/ibm/utils.go b/providers/ibm/utils.go new file mode 100644 index 000000000..b3c9e6072 --- /dev/null +++ b/providers/ibm/utils.go @@ -0,0 +1,191 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + gohttp "net/http" + "net/url" + "os" + "reflect" + "strconv" + "strings" + + bluemix "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/authentication" + "github.com/IBM-Cloud/bluemix-go/http" + "github.com/IBM-Cloud/bluemix-go/rest" + "github.com/IBM-Cloud/bluemix-go/session" + "github.com/dgrijalva/jwt-go" + + "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/managementv2" +) + +// UserConfig ... +type UserConfig struct { + userID string + userEmail string + userAccount string + cloudName string `default:"bluemix"` + cloudType string `default:"public"` + generation int `default:"2"` +} + +// EnvFallBack ... +func envFallBack(envs []string, defaultValue string) string { + for _, k := range envs { + if v := os.Getenv(k); v != "" { + return v + } + } + return defaultValue +} + +func fetchUserDetails(sess *session.Session, generation int) (*UserConfig, error) { + config := sess.Config + user := UserConfig{} + var bluemixToken string + + if strings.HasPrefix(config.IAMAccessToken, "Bearer") { + bluemixToken = config.IAMAccessToken[7:len(config.IAMAccessToken)] + } else { + bluemixToken = config.IAMAccessToken + } + + token, err := jwt.Parse(bluemixToken, func(token *jwt.Token) (interface{}, error) { + return "", nil + }) + // TODO validate with key + if err != nil && !strings.Contains(err.Error(), "key is of invalid type") { + return &user, err + } + claims := token.Claims.(jwt.MapClaims) + if email, ok := claims["email"]; ok { + user.userEmail = email.(string) + } + user.userID = claims["id"].(string) + user.userAccount = claims["account"].(map[string]interface{})["bss"].(string) + iss := claims["iss"].(string) + if strings.Contains(iss, "https://iam.cloud.ibm.com") { + user.cloudName = "bluemix" + } else { + user.cloudName = "staging" + } + user.cloudType = "public" + + user.generation = generation + return &user, nil +} + +func authenticateAPIKey(sess *session.Session) error { + config := sess.Config + tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ + DefaultHeader: gohttp.Header{ + "User-Agent": []string{http.UserAgent()}, + }, + }) + if err != nil { + return err + } + return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) +} + +func authenticateCF(sess *session.Session) error { + config := sess.Config + tokenRefresher, err := authentication.NewUAARepository(config, &rest.Client{ + DefaultHeader: gohttp.Header{ + "User-Agent": []string{http.UserAgent()}, + }, + }) + if err != nil { + return err + } + return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) +} + +func GetNext(next interface{}) string { + if reflect.ValueOf(next).IsNil() { + return "" + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) + if err != nil { + return "" + } + + q := u.Query() + return q.Get("start") +} + +// GetNextIAM ... +func GetNextIAM(next interface{}) string { + if reflect.ValueOf(next).IsNil() { + return "" + } + + u, err := url.Parse(reflect.ValueOf(next).Elem().String()) + if err != nil { + return "" + } + q := u.Query() + return q.Get("pagetoken") +} + +func GetResourceGroupID(apiKey, name, region string) (string, error) { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: apiKey, + Region: region, + } + + sess, err := session.New(bmxConfig) + if err != nil { + return "", err + } + + err = authenticateAPIKey(sess) + if err != nil { + return "", err + } + + generation := envFallBack([]string{"Generation"}, "2") + gen, err := strconv.Atoi(generation) + if err != nil { + return "", err + } + userInfo, err := fetchUserDetails(sess, gen) + if err != nil { + return "", err + } + + accountID := userInfo.userAccount + rsManagementAPI, err := managementv2.New(sess) + if err != nil { + return "", err + } + + rsGroup := rsManagementAPI.ResourceGroup() + resourceGroupQuery := &managementv2.ResourceGroupQuery{ + AccountID: accountID, + } + grp, err := rsGroup.FindByName(resourceGroupQuery, name) + if err != nil { + return "", err + } + if len(grp) > 0 { + return grp[0].ID, nil + } + + return "", fmt.Errorf("Unable to get ID of resource group") +} diff --git a/providers/ibm/vpc_cluster.go b/providers/ibm/vpc_cluster.go new file mode 100644 index 000000000..0f04a2d7b --- /dev/null +++ b/providers/ibm/vpc_cluster.go @@ -0,0 +1,92 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ibm + +import ( + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/IBM-Cloud/bluemix-go" + "github.com/IBM-Cloud/bluemix-go/api/container/containerv2" + "github.com/IBM-Cloud/bluemix-go/session" +) + +type VPCClusterGenerator struct { + IBMService +} + +func (g VPCClusterGenerator) loadcluster(clustersID, clusterName string) terraformutils.Resource { + resource := terraformutils.NewSimpleResource( + clustersID, + normalizeResourceName(clusterName, false), + "ibm_container_vpc_cluster", + "ibm", + []string{}) + return resource +} + +func (g VPCClusterGenerator) loadWorkerPools(clustersID, poolID, poolName string, dependsOn []string) terraformutils.Resource { + resource := terraformutils.NewResource( + fmt.Sprintf("%s/%s", clustersID, poolID), + normalizeResourceName(poolName, true), + "ibm_container_vpc_worker_pool", + "ibm", + map[string]string{}, + []string{}, + map[string]interface{}{ + "depends_on": dependsOn, + }) + return resource +} + +func (g *VPCClusterGenerator) InitResources() error { + bmxConfig := &bluemix.Config{ + BluemixAPIKey: os.Getenv("IC_API_KEY"), + } + sess, err := session.New(bmxConfig) + if err != nil { + return err + } + client, err := containerv2.New(sess) + if err != nil { + return err + } + + clusters, err := client.Clusters().List(containerv2.ClusterTargetHeader{}) + if err != nil { + return err + } + + for _, cs := range clusters { + g.Resources = append(g.Resources, g.loadcluster(cs.ID, cs.Name)) + resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName + workerPools, err := client.WorkerPools().ListWorkerPools(cs.ID, containerv2.ClusterTargetHeader{}) + if err != nil { + return err + } + + for _, pool := range workerPools { + if pool.PoolName != "default" { + var dependsOn []string + dependsOn = append(dependsOn, + "ibm_container_vpc_cluster."+resourceName) + g.Resources = append(g.Resources, g.loadWorkerPools(cs.ID, pool.ID, pool.PoolName, dependsOn)) + } + } + + } + return nil +} diff --git a/providers/kubernetes/kind.go b/providers/kubernetes/kind.go index 236e47d98..3837a2faa 100644 --- a/providers/kubernetes/kind.go +++ b/providers/kubernetes/kind.go @@ -15,6 +15,7 @@ package kubernetes import ( + "context" "reflect" "github.com/GoogleCloudPlatform/terraformer/terraformutils" @@ -54,9 +55,10 @@ func (k *Kind) InitResources() error { if k.Namespaced { param = append(param, reflect.ValueOf(namespace)) } + resource := group.MethodByName(extractClientSetFuncTypeName(k.Name)).Call(param)[0] - results := resource.MethodByName("List").Call([]reflect.Value{ + results := resource.MethodByName("List").Call([]reflect.Value{reflect.ValueOf(context.Background()), reflect.ValueOf(metav1.ListOptions{})}) if !results[1].IsNil() { diff --git a/providers/mackerel/alert_group_setting.go b/providers/mackerel/alert_group_setting.go new file mode 100644 index 000000000..16199e856 --- /dev/null +++ b/providers/mackerel/alert_group_setting.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// AlertGroupSettingGenerator ... +type AlertGroupSettingGenerator struct { + MackerelService +} + +func (g *AlertGroupSettingGenerator) createResources(alertGroupSettings []*mackerel.AlertGroupSetting) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, alertGroupSetting := range alertGroupSettings { + resources = append(resources, g.createResource(alertGroupSetting.ID)) + } + return resources +} + +func (g *AlertGroupSettingGenerator) createResource(alertGroupSettingID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + alertGroupSettingID, + fmt.Sprintf("alert_group_setting_%s", alertGroupSettingID), + "mackerel_alert_group_setting", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each alert group setting create 1 TerraformResource. +// Need Alert Group Setting ID as ID for terraform resource +func (g *AlertGroupSettingGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + alertGroupSettings, err := client.FindAlertGroupSettings() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(alertGroupSettings)...) + return nil +} diff --git a/providers/mackerel/aws_integration.go b/providers/mackerel/aws_integration.go new file mode 100644 index 000000000..313d937a0 --- /dev/null +++ b/providers/mackerel/aws_integration.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// AWSIntegrationGenerator ... +type AWSIntegrationGenerator struct { + MackerelService +} + +func (g *AWSIntegrationGenerator) createResources(awsIntegrations []*mackerel.AWSIntegration) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, awsIntegration := range awsIntegrations { + resources = append(resources, g.createResource(awsIntegration.ID)) + } + return resources +} + +func (g *AWSIntegrationGenerator) createResource(awsIntegrationID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + awsIntegrationID, + fmt.Sprintf("aws_integration_%s", awsIntegrationID), + "mackerel_aws_integration", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each aws integration create 1 TerraformResource. +// Need AWS Integration ID as ID for terraform resource +func (g *AWSIntegrationGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + awsIntegrations, err := client.FindAWSIntegrations() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(awsIntegrations)...) + return nil +} diff --git a/providers/mackerel/channel.go b/providers/mackerel/channel.go new file mode 100644 index 000000000..9c4abafd4 --- /dev/null +++ b/providers/mackerel/channel.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// ChannelGenerator ... +type ChannelGenerator struct { + MackerelService +} + +func (g *ChannelGenerator) createResources(channels []*mackerel.Channel) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, channel := range channels { + if channel.Type != "email" && channel.Type != "slack" && channel.Type != "webhook" { + continue + } + + if channel.Type == "email" { + if channel.Events != nil { + events := *channel.Events + for _, event := range events { + if event != "alert" && event != "alertGroup" { + continue + } + } + } else { + continue + } + } + + resources = append(resources, g.createResource(channel.ID)) + } + return resources +} + +func (g *ChannelGenerator) createResource(channelID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + channelID, + fmt.Sprintf("channel_%s", channelID), + "mackerel_channel", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each channel create 1 TerraformResource. +// Need Channel ID as ID for terraform resource +func (g *ChannelGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + channels, err := client.FindChannels() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(channels)...) + return nil +} diff --git a/providers/mackerel/downtime.go b/providers/mackerel/downtime.go new file mode 100644 index 000000000..b800a87b2 --- /dev/null +++ b/providers/mackerel/downtime.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// DowntimeGenerator ... +type DowntimeGenerator struct { + MackerelService +} + +func (g *DowntimeGenerator) createResources(downtimes []*mackerel.Downtime) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, downtime := range downtimes { + resources = append(resources, g.createResource(downtime.ID)) + } + return resources +} + +func (g *DowntimeGenerator) createResource(downtimeID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + downtimeID, + fmt.Sprintf("downtime_%s", downtimeID), + "mackerel_downtime", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each downtime create 1 TerraformResource. +// Need Downtime ID as ID for terraform resource +func (g *DowntimeGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + downtimes, err := client.FindDowntimes() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(downtimes)...) + return nil +} diff --git a/providers/mackerel/mackerel_provider.go b/providers/mackerel/mackerel_provider.go new file mode 100644 index 000000000..1ff057dc1 --- /dev/null +++ b/providers/mackerel/mackerel_provider.go @@ -0,0 +1,99 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + mackerel "github.com/mackerelio/mackerel-client-go" + "github.com/zclconf/go-cty/cty" +) + +type MackerelProvider struct { //nolint + terraformutils.Provider + apiKey string + mackerelClient *mackerel.Client +} + +// Init check env params and initialize API Client +func (p *MackerelProvider) Init(args []string) error { + if args[0] != "" { + p.apiKey = args[0] + } else { + if apiKey := os.Getenv("MACKEREL_API_KEY"); apiKey != "" { + p.apiKey = apiKey + } else { + return errors.New("api-key requirement") + } + } + // Initialize the Mackerel API client + p.mackerelClient = mackerel.NewClient(p.apiKey) + return nil +} + +// InitService ... +func (p *MackerelProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "api-key": p.apiKey, + "mackerelClient": p.mackerelClient, + }) + return nil +} + +// GetName return string of provider name for Mackerel +func (p *MackerelProvider) GetName() string { + return "mackerel" +} + +// GetConfig return map of provider config for Mackerel +func (p *MackerelProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "api_key": cty.StringVal(p.apiKey), + }) +} + +// GetSupportedService return map of support service for Mackerel +func (p *MackerelProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "alert_group_setting": &AlertGroupSettingGenerator{}, + "aws_integration": &AWSIntegrationGenerator{}, + "channel": &ChannelGenerator{}, + "downtime": &DowntimeGenerator{}, + "monitor": &MonitorGenerator{}, + "notification_group": &NotificationGroupGenerator{}, + "role": &RoleGenerator{}, + "service": &ServiceGenerator{}, + } +} + +// GetProviderData return map of provider data for Mackerel +func (p MackerelProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{} +} + +// GetResourceConnections return map of resource connections for Mackerel +func (p *MackerelProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} diff --git a/providers/mackerel/mackerel_service.go b/providers/mackerel/mackerel_service.go new file mode 100644 index 000000000..d1dfcec0a --- /dev/null +++ b/providers/mackerel/mackerel_service.go @@ -0,0 +1,21 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import "github.com/GoogleCloudPlatform/terraformer/terraformutils" + +type MackerelService struct { // nolint + terraformutils.Service +} diff --git a/providers/mackerel/monitor.go b/providers/mackerel/monitor.go new file mode 100644 index 000000000..787938262 --- /dev/null +++ b/providers/mackerel/monitor.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// MonitorGenerator ... +type MonitorGenerator struct { + MackerelService +} + +func (g *MonitorGenerator) createResources(monitors []mackerel.Monitor) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, monitor := range monitors { + resources = append(resources, g.createResource(monitor.MonitorID())) + } + return resources +} + +func (g *MonitorGenerator) createResource(monitorID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + monitorID, + fmt.Sprintf("monitor_%s", monitorID), + "mackerel_monitor", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each monitor create 1 TerraformResource. +// Need Monitor ID as ID for terraform resource +func (g *MonitorGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + monitors, err := client.FindMonitors() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(monitors)...) + return nil +} diff --git a/providers/mackerel/notification_group.go b/providers/mackerel/notification_group.go new file mode 100644 index 000000000..53fd72f82 --- /dev/null +++ b/providers/mackerel/notification_group.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// NotificationGroupGenerator ... +type NotificationGroupGenerator struct { + MackerelService +} + +func (g *NotificationGroupGenerator) createResources(notificationGroups []*mackerel.NotificationGroup) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, notificationGroup := range notificationGroups { + resources = append(resources, g.createResource(notificationGroup.ID)) + } + return resources +} + +func (g *NotificationGroupGenerator) createResource(notificationGroupID string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + notificationGroupID, + fmt.Sprintf("notification_group_%s", notificationGroupID), + "mackerel_notification_group", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each notification group create 1 TerraformResource. +// Need Notification Group ID as ID for terraform resource +func (g *NotificationGroupGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + notificationGroups, err := client.FindNotificationGroups() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(notificationGroups)...) + return nil +} diff --git a/providers/mackerel/role.go b/providers/mackerel/role.go new file mode 100644 index 000000000..2d6f6f2a2 --- /dev/null +++ b/providers/mackerel/role.go @@ -0,0 +1,71 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// RoleGenerator ... +type RoleGenerator struct { + MackerelService +} + +func (g *RoleGenerator) createResources(serviceName string, roles []*mackerel.Role) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, role := range roles { + resources = append(resources, g.createResource(serviceName, role.Name)) + } + return resources +} + +func (g *RoleGenerator) createResource(serviceName string, roleName string) terraformutils.Resource { + return terraformutils.NewResource( + fmt.Sprintf("%s:%s", serviceName, roleName), + fmt.Sprintf("role_%s_%s", serviceName, roleName), + "mackerel_role", + "mackerel", + map[string]string{ + "service": serviceName, + "name": roleName, + }, + []string{}, + map[string]interface{}{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each role create 1 TerraformResource. +// Need Service Name And Role Name as ID for terraform resource +func (g *RoleGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + + services, err := client.FindServices() + if err != nil { + return err + } + + for _, service := range services { + roles, err := client.FindRoles(service.Name) + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(service.Name, roles)...) + } + return nil +} diff --git a/providers/mackerel/service.go b/providers/mackerel/service.go new file mode 100644 index 000000000..153f2f3a6 --- /dev/null +++ b/providers/mackerel/service.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mackerel + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/mackerelio/mackerel-client-go" +) + +// ServiceGenerator ... +type ServiceGenerator struct { + MackerelService +} + +func (g *ServiceGenerator) createResources(services []*mackerel.Service) []terraformutils.Resource { + resources := []terraformutils.Resource{} + for _, service := range services { + resources = append(resources, g.createResource(service.Name)) + } + return resources +} + +func (g *ServiceGenerator) createResource(serviceName string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + serviceName, + fmt.Sprintf("service_%s", serviceName), + "mackerel_service", + "mackerel", + []string{}, + ) +} + +// InitResources Generate TerraformResources from Mackerel API, +// from each service create 1 TerraformResource. +// Need Service Name as ID for terraform resource +func (g *ServiceGenerator) InitResources() error { + client := g.Args["mackerelClient"].(*mackerel.Client) + services, err := client.FindServices() + if err != nil { + return err + } + g.Resources = append(g.Resources, g.createResources(services)...) + return nil +} diff --git a/providers/mikrotik/mikrotik_provider.go b/providers/mikrotik/mikrotik_provider.go index 441580b83..5365c540a 100644 --- a/providers/mikrotik/mikrotik_provider.go +++ b/providers/mikrotik/mikrotik_provider.go @@ -16,34 +16,19 @@ package mikrotik import ( "errors" - "os" "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/ddelnano/terraform-provider-mikrotik/client" ) type MikrotikProvider struct { //nolint terraformutils.Provider - host string - user string - password string + client.Mikrotik } func (p *MikrotikProvider) Init(args []string) error { - if os.Getenv("MIKROTIK_HOST") == "" { - return errors.New("set MIKROTIK_HOST env var") - } - p.host = os.Getenv("MIKROTIK_HOST") - - if os.Getenv("MIKROTIK_USER") == "" { - return errors.New("set MIKROTIK_USER env var") - } - p.user = os.Getenv("MIKROTIK_USER") - - if os.Getenv("MIKROTIK_PASSWORD") == "" { - return errors.New("set MIKROTIK_PASSWORD env var") - } - p.password = os.Getenv("MIKROTIK_PASSWORD") - + // The mikrotik provider gets its credentials through environment variables + // and therefore nothing needs to be done here return nil } @@ -55,8 +40,8 @@ func (p *MikrotikProvider) GetProviderData(arg ...string) map[string]interface{} return map[string]interface{}{ "provider": map[string]interface{}{ "mikrotik": map[string]interface{}{ - "host": p.host, - "user": p.user, + "host": p.Host, + "user": p.Username, }, }, } @@ -82,9 +67,12 @@ func (p *MikrotikProvider) InitService(serviceName string, verbose bool) error { p.Service.SetVerbose(verbose) p.Service.SetProviderName(p.GetName()) p.Service.SetArgs(map[string]interface{}{ - "host": p.host, - "user": p.user, - "password": p.password, + "host": p.Host, + "user": p.Username, + "password": p.Password, + "tls": p.TLS, + "ca_certificate": p.CA, + "insecure": p.Insecure, }) return nil } diff --git a/providers/mikrotik/mikrotik_service.go b/providers/mikrotik/mikrotik_service.go index b98d371ce..18232a49d 100644 --- a/providers/mikrotik/mikrotik_service.go +++ b/providers/mikrotik/mikrotik_service.go @@ -24,8 +24,6 @@ type MikrotikService struct { //nolint func (m *MikrotikService) generateClient() client.Mikrotik { return client.NewClient( - m.Args["host"].(string), - m.Args["user"].(string), - m.Args["password"].(string), + client.GetConfigFromEnv(), ) } diff --git a/providers/newrelic/newrelic_provider.go b/providers/newrelic/newrelic_provider.go index 27116e2c9..0e9b4866d 100644 --- a/providers/newrelic/newrelic_provider.go +++ b/providers/newrelic/newrelic_provider.go @@ -16,15 +16,48 @@ package newrelic import ( "errors" + "os" + "strconv" "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/zclconf/go-cty/cty" ) type NewRelicProvider struct { //nolint terraformutils.Provider + accountID int + APIKey string + Region string } func (p *NewRelicProvider) Init(args []string) error { + if apiKey := os.Getenv("NEW_RELIC_API_KEY"); apiKey != "" { + p.APIKey = os.Getenv("NEW_RELIC_API_KEY") + } + if accountIDs := os.Getenv("NEW_RELIC_ACCOUNT_ID"); accountIDs != "" { + accountID, err := strconv.Atoi(accountIDs) + if err != nil { + return err + + } + p.accountID = accountID + } + if len(args) > 0 { + p.APIKey = args[0] + } + if len(args) > 1 { + accountID, err := strconv.Atoi(args[1]) + if err != nil { + return err + } + p.accountID = accountID + } + if len(args) > 1 { + p.Region = args[2] + } + if p.Region == "" { + p.Region = "US" + } return nil } @@ -32,6 +65,14 @@ func (p *NewRelicProvider) GetName() string { return "newrelic" } +func (p *NewRelicProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "account_id": cty.NumberIntVal(int64(p.accountID)), + "api_key": cty.StringVal(p.APIKey), + "region": cty.StringVal(p.Region), + }) +} + func (p *NewRelicProvider) GetProviderData(arg ...string) map[string]interface{} { return map[string]interface{}{} } @@ -57,6 +98,7 @@ func (p *NewRelicProvider) InitService(serviceName string, verbose bool) error { p.Service = p.GetSupportedService()[serviceName] p.Service.SetName(serviceName) p.Service.SetVerbose(verbose) + p.Service.SetArgs(map[string]interface{}{"apiKey": p.APIKey}) p.Service.SetProviderName(p.GetName()) return nil diff --git a/providers/newrelic/newrelic_service.go b/providers/newrelic/newrelic_service.go index 5e4d901f5..27992b029 100644 --- a/providers/newrelic/newrelic_service.go +++ b/providers/newrelic/newrelic_service.go @@ -15,9 +15,6 @@ package newrelic import ( - "errors" - "os" - "github.com/GoogleCloudPlatform/terraformer/terraformutils" synthetics "github.com/dollarshaveclub/new-relic-synthetics-go" newrelic "github.com/paultyng/go-newrelic/v4/api" @@ -28,41 +25,18 @@ type NewRelicService struct { //nolint } func (s *NewRelicService) Client() (*newrelic.Client, error) { - apiKey := os.Getenv("NEWRELIC_API_KEY") - - if apiKey == "" { - err := errors.New("No NEWRELIC_API_KEY environment set") - return nil, err - } - - client := newrelic.New(newrelic.Config{APIKey: apiKey}) + client := newrelic.New(newrelic.Config{APIKey: s.GetArgs()["apiKey"].(string)}) return &client, nil } func (s *NewRelicService) InfraClient() (*newrelic.InfraClient, error) { - apiKey := os.Getenv("NEWRELIC_API_KEY") - - if apiKey == "" { - err := errors.New("No NEWRELIC_API_KEY environment set") - return nil, err - } - - client := newrelic.NewInfraClient(newrelic.Config{APIKey: apiKey, Debug: s.Verbose}) - + client := newrelic.NewInfraClient(newrelic.Config{APIKey: s.GetArgs()["apiKey"].(string), Debug: s.Verbose}) return &client, nil } func (s *NewRelicService) SyntheticsClient() (*synthetics.Client, error) { - apiKey := os.Getenv("NEWRELIC_API_KEY") - - if apiKey == "" { - err := errors.New("No NEWRELIC_API_KEY environment set") - return nil, err - } - conf := func(c *synthetics.Client) { - c.APIKey = apiKey + c.APIKey = s.GetArgs()["apiKey"].(string) } - return synthetics.NewClient(conf) } diff --git a/providers/okta/app.go b/providers/okta/app.go new file mode 100644 index 000000000..11522be39 --- /dev/null +++ b/providers/okta/app.go @@ -0,0 +1,69 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/okta/okta-sdk-golang/v2/okta" +) + +//NOTE: Okta SDK v2.6.1 ListApplications() method does not support applications by type at this time. So +// we have to create the application filter by our self. +func getApplications(ctx context.Context, client *okta.Client, signOnMode string) ([]*okta.Application, error) { + supportedApps, err := getAllApplications(ctx, client) + if err != nil { + return nil, err + } + + var filterApps []*okta.Application + for _, app := range supportedApps { + if app.SignOnMode == signOnMode { + filterApps = append(filterApps, app) + } + } + return filterApps, nil +} + +func getAllApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + apps, resp, err := client.Application.ListApplications(ctx, nil) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextAppSet []okta.App + resp, err = resp.Next(ctx, &nextAppSet) + if err != nil { + return nil, err + } + apps = append(apps, nextAppSet...) + } + + var supportedApps []*okta.Application + for _, app := range apps { + //NOTE: Okta provider does not support the following app type/name + if app.(*okta.Application).Name == "template_wsfed" || + app.(*okta.Application).Name == "template_swa_two_page" || + app.(*okta.Application).Name == "okta_enduser" || + app.(*okta.Application).Name == "okta_browser_plugin" || + app.(*okta.Application).Name == "saasure" { + continue + } + supportedApps = append(supportedApps, app.(*okta.Application)) + } + + return supportedApps, nil +} diff --git a/providers/okta/app_auto_login.go b/providers/okta/app_auto_login.go new file mode 100644 index 000000000..d031b7b17 --- /dev/null +++ b/providers/okta/app_auto_login.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppAutoLoginGenerator struct { + OktaService +} + +func (g AppAutoLoginGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_auto_login", + "okta", + []string{})) + } + return resources +} + +func (g *AppAutoLoginGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getAutoLoginApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getAutoLoginApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "AUTO_LOGIN" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + return apps, nil +} diff --git a/providers/okta/app_basic_auth.go b/providers/okta/app_basic_auth.go new file mode 100644 index 000000000..21eac34d2 --- /dev/null +++ b/providers/okta/app_basic_auth.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppBasicAuthGenerator struct { + OktaService +} + +func (g AppBasicAuthGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_basic_auth", + "okta", + []string{})) + } + return resources +} + +func (g *AppBasicAuthGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getBasicAuthApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getBasicAuthApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "BASIC_AUTH" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + return apps, nil +} diff --git a/providers/okta/app_bookmark.go b/providers/okta/app_bookmark.go new file mode 100644 index 000000000..f1a2aaa5f --- /dev/null +++ b/providers/okta/app_bookmark.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppBookmarkGenerator struct { + OktaService +} + +func (g AppBookmarkGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_bookmark", + "okta", + []string{})) + } + return resources +} + +func (g *AppBookmarkGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getBookmarkApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getBookmarkApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "BOOKMARK" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + return apps, nil +} diff --git a/providers/okta/app_oauth.go b/providers/okta/app_oauth.go new file mode 100644 index 000000000..2031a30ef --- /dev/null +++ b/providers/okta/app_oauth.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppOAuthGenerator struct { + OktaService +} + +func (g AppOAuthGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_oauth", + "okta", + []string{})) + } + return resources +} + +// Generate Terraform Resources from Okta API, +func (g *AppOAuthGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getOAuthApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getOAuthApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "OPENID_CONNECT" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + return apps, nil +} diff --git a/providers/okta/app_saml.go b/providers/okta/app_saml.go new file mode 100644 index 000000000..a7bdee20f --- /dev/null +++ b/providers/okta/app_saml.go @@ -0,0 +1,57 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppSamlGenerator struct { + OktaService +} + +func (g AppSamlGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_saml", + "okta", + []string{})) + } + return resources +} + +func (g *AppSamlGenerator) InitResources() error { + signOnMode := []string{"SAML_1_1", "SAML_2_0"} + allSamlApps := []*okta.Application{} + for _, signOnMode := range signOnMode { + ctx, client, err := g.Client() + if err != nil { + return err + } + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return err + } + + allSamlApps = append(allSamlApps, apps...) + } + + g.Resources = g.createResources(allSamlApps) + return nil +} diff --git a/providers/okta/app_secure_password_store.go b/providers/okta/app_secure_password_store.go new file mode 100644 index 000000000..6b5f93dd1 --- /dev/null +++ b/providers/okta/app_secure_password_store.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppSecurePasswordStoreGenerator struct { + OktaService +} + +func (g AppSecurePasswordStoreGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_secure_password_store", + "okta", + []string{})) + } + return resources +} + +func (g *AppSecurePasswordStoreGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getSecurePasswordStoreApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getSecurePasswordStoreApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "SECURE_PASSWORD_STORE" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + return apps, nil +} diff --git a/providers/okta/app_swa.go b/providers/okta/app_swa.go new file mode 100644 index 000000000..a34fe3608 --- /dev/null +++ b/providers/okta/app_swa.go @@ -0,0 +1,71 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppSWAGenerator struct { + OktaService +} + +func (g AppSWAGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_swa", + "okta", + []string{})) + } + return resources +} + +func (g *AppSWAGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getSWAApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getSWAApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "BROWSER_PLUGIN" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + swaApps := []*okta.Application{} + for _, app := range apps { + if app.Name == "template_swa" { + swaApps = append(swaApps, app) + } + } + + return swaApps, nil +} diff --git a/providers/okta/app_three_field.go b/providers/okta/app_three_field.go new file mode 100644 index 000000000..742b03eaa --- /dev/null +++ b/providers/okta/app_three_field.go @@ -0,0 +1,71 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppThreeFieldGenerator struct { + OktaService +} + +func (g AppThreeFieldGenerator) createResources(appList []*okta.Application) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, app := range appList { + resources = append(resources, terraformutils.NewSimpleResource( + app.Id, + normalizeResourceName(app.Id+"_"+app.Name), + "okta_app_three_field", + "okta", + []string{})) + } + return resources +} + +func (g *AppThreeFieldGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getThreeFieldApplications(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(apps) + return nil +} + +func getThreeFieldApplications(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { + signOnMode := "BROWSER_PLUGIN" + apps, err := getApplications(ctx, client, signOnMode) + if err != nil { + return nil, err + } + + threeFieldApps := []*okta.Application{} + for _, app := range apps { + if app.Name == "template_swa3field" { + threeFieldApps = append(threeFieldApps, app) + } + } + + return threeFieldApps, nil +} diff --git a/providers/okta/app_user_schema.go b/providers/okta/app_user_schema.go new file mode 100644 index 000000000..2738c6def --- /dev/null +++ b/providers/okta/app_user_schema.go @@ -0,0 +1,82 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AppUserSchemaPropertyGenerator struct { + OktaService +} + +func (g AppUserSchemaPropertyGenerator) createResources(appUserSchema *okta.UserSchema, appID string) []terraformutils.Resource { + var resources []terraformutils.Resource + for index := range appUserSchema.Definitions.Custom.Properties { + resources = append(resources, terraformutils.NewResource( + index, + normalizeResourceName(appID)+"_property_"+normalizeResourceName(index), + "okta_app_user_schema_property", + "okta", + map[string]string{ + "app_id": appID, + "index": index, + }, + []string{}, + map[string]interface{}{}, + )) + } + + for index := range appUserSchema.Definitions.Base.Properties { + resources = append(resources, terraformutils.NewResource( + index, + normalizeResourceName(appID)+"_property_"+normalizeResourceName(index), + "okta_app_user_base_schema_property", + "okta", + map[string]string{ + "app_id": appID, + "index": index, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resources +} + +func (g *AppUserSchemaPropertyGenerator) InitResources() error { + var resources []terraformutils.Resource + ctx, client, e := g.Client() + if e != nil { + return e + } + + apps, err := getAllApplications(ctx, client) + if err != nil { + return err + } + + for _, app := range apps { + appUserSchema, _, err := client.UserSchema.GetApplicationUserSchema(ctx, app.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(appUserSchema, app.Id)...) + } + g.Resources = resources + return nil +} diff --git a/providers/okta/authorization_server.go b/providers/okta/authorization_server.go new file mode 100644 index 000000000..36523fcb9 --- /dev/null +++ b/providers/okta/authorization_server.go @@ -0,0 +1,74 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AuthorizationServerGenerator struct { + OktaService +} + +func (g AuthorizationServerGenerator) createResources(authorizationServerList []*okta.AuthorizationServer) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, authorizationServer := range authorizationServerList { + resourceType := "okta_auth_server" + if authorizationServer.Name == "default" { + resourceType = "okta_auth_server_default" + } + + resources = append(resources, terraformutils.NewSimpleResource( + authorizationServer.Id, + "auth_server_"+authorizationServer.Name, + resourceType, + "okta", + []string{})) + } + return resources +} + +func (g *AuthorizationServerGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, err := getAuthorizationServers(ctx, client) + if err != nil { + return e + } + + g.Resources = g.createResources(output) + return nil +} + +func getAuthorizationServers(ctx context.Context, client *okta.Client) ([]*okta.AuthorizationServer, error) { + output, resp, err := client.AuthorizationServer.ListAuthorizationServers(ctx, nil) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextAuthorizationServerSet []*okta.AuthorizationServer + resp, _ = resp.Next(ctx, &nextAuthorizationServerSet) + output = append(output, nextAuthorizationServerSet...) + } + + return output, nil +} diff --git a/providers/okta/authorization_server_claim.go b/providers/okta/authorization_server_claim.go new file mode 100644 index 000000000..89fa1d2ae --- /dev/null +++ b/providers/okta/authorization_server_claim.go @@ -0,0 +1,72 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AuthorizationServerClaimGenerator struct { + OktaService +} + +func (g AuthorizationServerClaimGenerator) createResources(authorizationServerClaimList []*okta.OAuth2Claim, authorizationServerID string, authorizationServerName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, authorizationServerClaim := range authorizationServerClaimList { + resourceType := "okta_auth_server_claim" + if authorizationServerClaim.Name == "sub" { + resourceType = "okta_auth_server_claim_default" + } + resources = append(resources, terraformutils.NewResource( + authorizationServerClaim.Id, + normalizeResourceName("auth_server_"+authorizationServerName+"_claim_"+authorizationServerClaim.Id), + resourceType, + "okta", + map[string]string{ + "auth_server_id": authorizationServerID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resources +} + +func (g *AuthorizationServerClaimGenerator) InitResources() error { + var resources []terraformutils.Resource + ctx, client, e := g.Client() + if e != nil { + return e + } + + authorizationServers, err := getAuthorizationServers(ctx, client) + if err != nil { + return err + } + + for _, authorizationServer := range authorizationServers { + output, _, err := client.AuthorizationServer.ListOAuth2Claims(ctx, authorizationServer.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, authorizationServer.Id, authorizationServer.Name)...) + } + + g.Resources = resources + return nil +} diff --git a/providers/okta/authorization_server_policy.go b/providers/okta/authorization_server_policy.go new file mode 100644 index 000000000..9586b1dd4 --- /dev/null +++ b/providers/okta/authorization_server_policy.go @@ -0,0 +1,68 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AuthorizationServerPolicyGenerator struct { + OktaService +} + +func (g AuthorizationServerPolicyGenerator) createResources(authorizationServerPolicyList []*okta.AuthorizationServerPolicy, authorizationServerID string, authorizationServerName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, authorizationServerPolicy := range authorizationServerPolicyList { + resources = append(resources, terraformutils.NewResource( + authorizationServerPolicy.Id, + normalizeResourceName("auth_server_"+authorizationServerName+"_policy_"+authorizationServerPolicy.Name), + "okta_auth_server_policy", + "okta", + map[string]string{ + "auth_server_id": authorizationServerID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resources +} + +func (g *AuthorizationServerPolicyGenerator) InitResources() error { + var resources []terraformutils.Resource + ctx, client, e := g.Client() + if e != nil { + return e + } + + authorizationServers, err := getAuthorizationServers(ctx, client) + if err != nil { + return err + } + + for _, authorizationServer := range authorizationServers { + output, _, err := client.AuthorizationServer.ListAuthorizationServerPolicies(ctx, authorizationServer.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, authorizationServer.Id, authorizationServer.Name)...) + } + + g.Resources = resources + return nil +} diff --git a/providers/okta/authorization_server_scope.go b/providers/okta/authorization_server_scope.go new file mode 100644 index 000000000..7e470357f --- /dev/null +++ b/providers/okta/authorization_server_scope.go @@ -0,0 +1,68 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type AuthorizationServerScopeGenerator struct { + OktaService +} + +func (g AuthorizationServerScopeGenerator) createResources(authorizationServerScopeList []*okta.OAuth2Scope, authorizationServerID string, authorizationServerName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, authorizationServerScope := range authorizationServerScopeList { + resources = append(resources, terraformutils.NewResource( + authorizationServerScope.Id, + normalizeResourceName("auth_server_"+authorizationServerName+"_scope_"+authorizationServerScope.Name), + "okta_auth_server_scope", + "okta", + map[string]string{ + "auth_server_id": authorizationServerID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resources +} + +func (g *AuthorizationServerScopeGenerator) InitResources() error { + var resources []terraformutils.Resource + ctx, client, e := g.Client() + if e != nil { + return e + } + + authorizationServers, err := getAuthorizationServers(ctx, client) + if err != nil { + return err + } + + for _, authorizationServer := range authorizationServers { + output, _, err := client.AuthorizationServer.ListOAuth2Scopes(ctx, authorizationServer.Id, nil) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, authorizationServer.Id, authorizationServer.Name)...) + } + + g.Resources = resources + return nil +} diff --git a/providers/okta/event_hook.go b/providers/okta/event_hook.go new file mode 100644 index 000000000..bdc6eabb5 --- /dev/null +++ b/providers/okta/event_hook.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type EventHookGenerator struct { + OktaService +} + +func (g EventHookGenerator) createResources(eventHookList []*okta.EventHook) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, eventHook := range eventHookList { + + resources = append(resources, terraformutils.NewSimpleResource( + eventHook.Id, + "event_hook_"+eventHook.Name, + "okta_event_hook", + "okta", + []string{})) + } + return resources +} + +func (g *EventHookGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.EventHook.ListEventHooks(ctx) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextEventHookSet []*okta.EventHook + resp, _ = resp.Next(ctx, &nextEventHookSet) + output = append(output, nextEventHookSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/factor.go b/providers/okta/factor.go new file mode 100644 index 000000000..fed75f0b7 --- /dev/null +++ b/providers/okta/factor.go @@ -0,0 +1,120 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/terraform-provider-okta/sdk" +) + +type FactorGenerator struct { + OktaService +} + +func (g FactorGenerator) createResources(ctx context.Context, factorList []*okta.UserFactor, client *sdk.APISupplement) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, factor := range factorList { + if factor.Status == "ACTIVE" { + resources = append(resources, terraformutils.NewResource( + factor.Id, + "factor_"+normalizeResourceNameWithRandom(factor.Id, true), + "okta_factor", + "okta", + map[string]string{ + "provider_id": factor.Id, + }, + []string{}, + map[string]interface{}{}, + )) + + if factor.FactorType == "token:hotp" { + hotpFactorProfiles, _, _ := getHotpFactorProfiles(ctx, client) + + for _, factorProfile := range hotpFactorProfiles { + if factorProfile != nil { + resources = append(resources, terraformutils.NewResource( + factorProfile.ID, + "factor_totp_"+normalizeResourceNameWithRandom(factorProfile.Name, true), + "okta_factor_totp", + "okta", + map[string]string{}, + []string{}, + map[string]interface{}{ + "name": factorProfile.Name, + "otp_length": factorProfile.Settings.OtpLength, + "time_step": factorProfile.Settings.TimeStep, + "clock_drift_interval": factorProfile.Settings.AcceptableAdjacentIntervals, + "shared_secret_encoding": factorProfile.Settings.Encoding, + "hmac_algorithm": factorProfile.Settings.TimeStep, + }, + )) + } + } + } + } + } + return resources +} + +func (g *FactorGenerator) InitResources() error { + var factors []*okta.UserFactor + + ctx, client, err := g.APISupplementClient() + if err != nil { + return err + } + + output, _, err := getListFactors(ctx, client) + if err != nil { + return err + } + + factors = append(factors, output...) + + g.Resources = g.createResources(ctx, factors, client) + return nil +} + +func getListFactors(ctx context.Context, m *sdk.APISupplement) ([]*okta.UserFactor, *okta.Response, error) { + //NOTE: Okta SDK does not support general ListFactors method so we got to manually implement the REST calls. + url := "/api/v1/org/factors" + req, err := m.RequestExecutor.NewRequest("GET", url, nil) + if err != nil { + return nil, nil, err + } + var factors []*okta.UserFactor + resp, err := m.RequestExecutor.Do(ctx, req, &factors) + if err != nil { + return nil, resp, err + } + return factors, resp, nil +} + +func getHotpFactorProfiles(ctx context.Context, m *sdk.APISupplement) ([]*sdk.HotpFactorProfile, *okta.Response, error) { + url := "/api/v1/org/factors/hotp/profiles" + req, err := m.RequestExecutor.NewRequest("GET", url, nil) + if err != nil { + return nil, nil, err + } + var factors []*sdk.HotpFactorProfile + resp, err := m.RequestExecutor.Do(ctx, req, &factors) + if err != nil { + return nil, resp, err + } + return factors, resp, nil +} diff --git a/providers/okta/group.go b/providers/okta/group.go new file mode 100644 index 000000000..e73a95187 --- /dev/null +++ b/providers/okta/group.go @@ -0,0 +1,61 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type GroupGenerator struct { + OktaService +} + +func (g GroupGenerator) createResources(groupList []*okta.Group) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, group := range groupList { + + resources = append(resources, terraformutils.NewSimpleResource( + group.Id, + "group_"+group.Profile.Name, + "okta_group", + "okta", + []string{})) + } + return resources +} + +func (g *GroupGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + filter := query.NewQueryParams(query.WithFilter("type eq \"OKTA_GROUP\"")) + output, resp, err := client.Group.ListGroups(ctx, filter) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextGroupSet []*okta.Group + resp, _ = resp.Next(ctx, &nextGroupSet) + output = append(output, nextGroupSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/group_rule.go b/providers/okta/group_rule.go new file mode 100644 index 000000000..9f8353891 --- /dev/null +++ b/providers/okta/group_rule.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type GroupRuleGenerator struct { + OktaService +} + +func (g GroupRuleGenerator) createResources(groupRuleList []*okta.GroupRule) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, groupRule := range groupRuleList { + + resources = append(resources, terraformutils.NewSimpleResource( + groupRule.Id, + "grouprule_"+groupRule.Name, + "okta_group_rule", + "okta", + []string{})) + } + return resources +} + +func (g *GroupRuleGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.Group.ListGroupRules(ctx, nil) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextGroupRuleSet []*okta.GroupRule + resp, _ = resp.Next(ctx, &nextGroupRuleSet) + output = append(output, nextGroupRuleSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/helpers.go b/providers/okta/helpers.go new file mode 100644 index 000000000..74cf11709 --- /dev/null +++ b/providers/okta/helpers.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "fmt" + "math/rand" + "regexp" + "strings" +) + +// Making resource's name less ugly +func normalizeResourceName(s string) string { + specialChars := `<>()*#{}[]|@_ .%'",&` + for _, c := range specialChars { + s = strings.ReplaceAll(s, string(c), "-") + } + + s = regexp.MustCompile(`^[^a-zA-Z_]+`).ReplaceAllLiteralString(s, "") + s = strings.TrimSuffix(s, "-") + + return strings.ToLower(s) +} + +func normalizeResourceNameWithRandom(s string, rand bool) string { + specialChars := `-<>()*#{}[]|@_ .%'",&` + for _, c := range specialChars { + s = strings.ReplaceAll(s, string(c), "_") + } + s = regexp.MustCompile(`^[^a-zA-Z_]+`).ReplaceAllLiteralString(s, "") + s = strings.TrimSuffix(s, "`_") + if rand { + randString := RandStringBytes(4) + return fmt.Sprintf("%s_%s", strings.ToLower(s), randString) + } + return strings.ToLower(s) +} + +const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789" + +func RandStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} diff --git a/providers/okta/idp_oidc.go b/providers/okta/idp_oidc.go new file mode 100644 index 000000000..45e9f9e2c --- /dev/null +++ b/providers/okta/idp_oidc.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type IdpOIDCGenerator struct { + OktaService +} + +func (g IdpOIDCGenerator) createResources(idpOIDCList []*okta.IdentityProvider) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, idp := range idpOIDCList { + resources = append(resources, terraformutils.NewSimpleResource( + idp.Id, + "idp_"+normalizeResourceName(idp.Type+"_"+idp.Name), + "okta_idp_oidc", + "okta", + []string{})) + + } + return resources +} + +func (g *IdpOIDCGenerator) InitResources() error { + ctx, client, err := g.Client() + if err != nil { + return err + } + + identityProviders, err := getIdpOIDC(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(identityProviders) + return nil +} + +func getIdpOIDC(ctx context.Context, client *okta.Client) ([]*okta.IdentityProvider, error) { + qp := &query.Params{Type: "OIDC", Limit: 1} + output, resp, err := client.IdentityProvider.ListIdentityProviders(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextIdpOIDCSet []*okta.IdentityProvider + resp, _ = resp.Next(ctx, &nextIdpOIDCSet) + output = append(output, nextIdpOIDCSet...) + } + + return output, nil +} diff --git a/providers/okta/idp_saml.go b/providers/okta/idp_saml.go new file mode 100644 index 000000000..c344c08eb --- /dev/null +++ b/providers/okta/idp_saml.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type IdpSAMLGenerator struct { + OktaService +} + +func (g IdpSAMLGenerator) createResources(idpSAMLList []*okta.IdentityProvider) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, idp := range idpSAMLList { + resources = append(resources, terraformutils.NewSimpleResource( + idp.Id, + "idp_"+normalizeResourceName(idp.Type+"_"+idp.Name), + "okta_idp_saml", + "okta", + []string{})) + + } + return resources +} + +func (g *IdpSAMLGenerator) InitResources() error { + ctx, client, err := g.Client() + if err != nil { + return err + } + + identityProviders, err := getIdpSAML(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(identityProviders) + return nil +} + +func getIdpSAML(ctx context.Context, client *okta.Client) ([]*okta.IdentityProvider, error) { + qp := &query.Params{Type: "SAML2", Limit: 1} + output, resp, err := client.IdentityProvider.ListIdentityProviders(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextIdpSAMLSet []*okta.IdentityProvider + resp, err = resp.Next(ctx, &nextIdpSAMLSet) + if err != nil { + return nil, err + } + output = append(output, nextIdpSAMLSet...) + } + + return output, nil +} diff --git a/providers/okta/idp_social.go b/providers/okta/idp_social.go new file mode 100644 index 000000000..13b5d827a --- /dev/null +++ b/providers/okta/idp_social.go @@ -0,0 +1,80 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type IdpSocialGenerator struct { + OktaService +} + +func (g IdpSocialGenerator) createResources(idpSocialList []*okta.IdentityProvider) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, idp := range idpSocialList { + resources = append(resources, terraformutils.NewSimpleResource( + idp.Id, + "idp_"+normalizeResourceName(idp.Type+"_"+idp.Name), + "okta_idp_social", + "okta", + []string{})) + + } + return resources +} + +// Generate Terraform Resources from Okta API, +func (g *IdpSocialGenerator) InitResources() error { + ctx, client, err := g.Client() + if err != nil { + return err + } + + identityProviders, err := getIdpSocials(ctx, client) + if err != nil { + return err + } + + g.Resources = g.createResources(identityProviders) + return nil +} + +func getIdpSocials(ctx context.Context, client *okta.Client) ([]*okta.IdentityProvider, error) { + idpSocialTypes := []string{"APPLE", "FACEBOOK", "GOOGLE", "LINKEDIN", "MICROSOFT"} + var allIDPSocials []*okta.IdentityProvider + + for _, idpSocialType := range idpSocialTypes { + qp := &query.Params{Type: idpSocialType, Limit: 1} + output, resp, err := client.IdentityProvider.ListIdentityProviders(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextIdpSocialSet []*okta.IdentityProvider + resp, _ = resp.Next(ctx, &nextIdpSocialSet) + output = append(output, nextIdpSocialSet...) + } + + allIDPSocials = append(allIDPSocials, output...) + } + + return allIDPSocials, nil +} diff --git a/providers/okta/inline_hook.go b/providers/okta/inline_hook.go new file mode 100644 index 000000000..56d56fbc3 --- /dev/null +++ b/providers/okta/inline_hook.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type InlineHookGenerator struct { + OktaService +} + +func (g InlineHookGenerator) createResources(inlineHookList []*okta.InlineHook) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, inlineHook := range inlineHookList { + + resources = append(resources, terraformutils.NewSimpleResource( + inlineHook.Id, + "inline_hook_"+inlineHook.Name, + "okta_inline_hook", + "okta", + []string{})) + } + return resources +} + +func (g *InlineHookGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.InlineHook.ListInlineHooks(ctx, nil) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextInlineHookSet []*okta.InlineHook + resp, _ = resp.Next(ctx, &nextInlineHookSet) + output = append(output, nextInlineHookSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/network_zone.go b/providers/okta/network_zone.go new file mode 100644 index 000000000..1c91c9206 --- /dev/null +++ b/providers/okta/network_zone.go @@ -0,0 +1,88 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type NetworkZoneGenerator struct { + OktaService +} + +func (g NetworkZoneGenerator) createResources(networkZoneList []*okta.NetworkZone) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, networkZone := range networkZoneList { + + resources = append(resources, terraformutils.NewResource( + networkZone.Id, + networkZone.Name, + "okta_network_zone", + "okta", + map[string]string{ + "name": networkZone.Name, + "type": networkZone.Type, + }, + []string{}, + attributesNetworkZone(networkZone), + )) + } + return resources +} + +func (g *NetworkZoneGenerator) InitResources() error { + ctx, client, err := g.Client() + if err != nil { + return err + } + + output, resp, err := client.NetworkZone.ListNetworkZones(ctx, nil) + if err != nil { + return err + } + + for resp.HasNextPage() { + var networkZoneSet []*okta.NetworkZone + resp, _ = resp.Next(ctx, &networkZoneSet) + output = append(output, networkZoneSet...) + } + + g.Resources = g.createResources(output) + return nil +} + +func attributesNetworkZone(networkZone *okta.NetworkZone) map[string]interface{} { + attributes := map[string]interface{}{} + attributes["usage"] = networkZone.Usage + + if networkZone.Type == "DYNAMIC" { + if networkZone.Locations != nil { + attributes["dynamic_locations"] = networkZone.Locations + } + } else if networkZone.Type == "IP" { + switch { + case networkZone.Proxies != nil && networkZone.Gateways != nil: + attributes["proxies"] = networkZone.Proxies + attributes["gateways"] = networkZone.Gateways + case networkZone.Proxies != nil && networkZone.Gateways == nil: + attributes["proxies"] = networkZone.Proxies + case networkZone.Proxies == nil && networkZone.Gateways != nil: + attributes["gateways"] = networkZone.Gateways + } + } + + return attributes +} diff --git a/providers/okta/okta_provider.go b/providers/okta/okta_provider.go new file mode 100644 index 000000000..844dd3cad --- /dev/null +++ b/providers/okta/okta_provider.go @@ -0,0 +1,127 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper" +) + +type OktaProvider struct { //nolint + terraformutils.Provider + orgName string + baseURL string + apiToken string +} + +func (p *OktaProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "okta": map[string]interface{}{ + "version": providerwrapper.GetProviderVersion(p.GetName()), + }, + }, + } +} + +func (p *OktaProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{ + "alerts": {"alert_notification_endpoints": []string{"alert_notification_endpoints", "id"}}, + } +} + +func (p *OktaProvider) Init(args []string) error { + orgName := os.Getenv("OKTA_ORG_NAME") + if orgName == "" { + return errors.New("set OKTA_ORG_NAME env var") + } + p.orgName = orgName + + baseURL := os.Getenv("OKTA_BASE_URL") + if baseURL == "" { + return errors.New("set OKTA_BASE_URL env var") + } + p.baseURL = baseURL + + apiToken := os.Getenv("OKTA_API_TOKEN") + if apiToken == "" { + return errors.New("set OKTA_API_TOKEN env var") + } + p.apiToken = apiToken + + return nil +} + +func (p *OktaProvider) GetName() string { + return "okta" +} + +func (p *OktaProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " is not a supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetProviderName(p.GetName()) + p.Service.SetVerbose(verbose) + p.Service.SetArgs(map[string]interface{}{ + "org_name": p.orgName, + "base_url": p.baseURL, + "api_token": p.apiToken, + }) + return nil +} + +func (p *OktaProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "okta_app_three_field": &AppThreeFieldGenerator{}, + "okta_app_swa": &AppSWAGenerator{}, + "okta_app_secure_password_store": &AppSecurePasswordStoreGenerator{}, + "okta_app_basic_auth": &AppBasicAuthGenerator{}, + "okta_app_auto_login": &AppAutoLoginGenerator{}, + "okta_app_bookmark": &AppBookmarkGenerator{}, + "okta_app_saml": &AppSamlGenerator{}, + "okta_app_oauth": &AppOAuthGenerator{}, + "okta_idp_oidc": &IdpOIDCGenerator{}, + "okta_idp_saml": &IdpSAMLGenerator{}, + "okta_idp_social": &IdpSocialGenerator{}, + "okta_factor": &FactorGenerator{}, + "okta_network_zone": &NetworkZoneGenerator{}, + "okta_trusted_origin": &TrustedOriginGenerator{}, + "okta_user": &UserGenerator{}, + "okta_template_sms": &SMSTemplateGenerator{}, + "okta_user_type": &UserTypeGenerator{}, + "okta_group": &GroupGenerator{}, + "okta_group_rule": &GroupRuleGenerator{}, + "okta_event_hook": &EventHookGenerator{}, + "okta_inline_hook": &EventHookGenerator{}, + "okta_policy_password": &PasswordPolicyGenerator{}, + "okta_policy_rule_password": &PasswordPolicyRuleGenerator{}, + "okta_policy_signon": &SignOnPolicyGenerator{}, + "okta_policy_rule_signon": &SignOnPolicyRuleGenerator{}, + "okta_policy_mfa": &MFAPolicyGenerator{}, + "okta_policy_rule_mfa": &MFAPolicyRuleGenerator{}, + "okta_auth_server": &AuthorizationServerGenerator{}, + "okta_auth_server_scope": &AuthorizationServerScopeGenerator{}, + "okta_auth_server_claim": &AuthorizationServerClaimGenerator{}, + "okta_auth_server_policy": &AuthorizationServerPolicyGenerator{}, + "okta_user_schema": &UserSchemaPropertyGenerator{}, + "okta_app_user_schema": &AppUserSchemaPropertyGenerator{}, + } +} diff --git a/providers/okta/okta_service.go b/providers/okta/okta_service.go new file mode 100644 index 000000000..d44c35e31 --- /dev/null +++ b/providers/okta/okta_service.go @@ -0,0 +1,70 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/terraform-provider-okta/sdk" +) + +type OktaService struct { //nolint + terraformutils.Service +} + +func (s *OktaService) Client() (context.Context, *okta.Client, error) { + orgName := s.Args["org_name"].(string) + baseURL := s.Args["base_url"].(string) + apiToken := s.Args["api_token"].(string) + + orgURL := fmt.Sprintf("https://%v.%v", orgName, baseURL) + + ctx, client, err := okta.NewClient( + context.Background(), + okta.WithOrgUrl(orgURL), + okta.WithToken(apiToken), + ) + if err != nil { + return ctx, nil, err + } + + return ctx, client, nil +} + +func (s *OktaService) APISupplementClient() (context.Context, *sdk.APISupplement, error) { + baseURL := s.Args["base_url"].(string) + orgName := s.Args["org_name"].(string) + apiToken := s.Args["api_token"].(string) + + orgURL := fmt.Sprintf("https://%v.%v", orgName, baseURL) + + ctx, client, err := okta.NewClient( + context.Background(), + okta.WithOrgUrl(orgURL), + okta.WithToken(apiToken), + ) + if err != nil { + return ctx, nil, err + } + + apiSupplementClient := &sdk.APISupplement{ + RequestExecutor: client.CloneRequestExecutor(), + } + + return ctx, apiSupplementClient, nil +} diff --git a/providers/okta/policy_mfa.go b/providers/okta/policy_mfa.go new file mode 100644 index 000000000..7c28f8edb --- /dev/null +++ b/providers/okta/policy_mfa.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type MFAPolicyGenerator struct { + OktaService +} + +func (g MFAPolicyGenerator) createResources(mfaPolicyList []*okta.Policy) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, mfaPolicy := range mfaPolicyList { + resourceName := normalizeResourceName(mfaPolicy.Name) + resourceType := "okta_policy_mfa" + if mfaPolicy.Name == "Default Policy" { + resourceType = "okta_policy_mfa_default" + } + resources = append(resources, terraformutils.NewSimpleResource( + mfaPolicy.Id, + "policy_mfa_"+resourceName, + resourceType, + "okta", + []string{})) + } + return resources +} + +func (g *MFAPolicyGenerator) InitResources() error { + var output []*okta.Policy + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, _ = getMFAPolicies(ctx, client) + g.Resources = g.createResources(output) + return nil +} + +func getMFAPolicies(ctx context.Context, client *okta.Client) ([]*okta.Policy, error) { + qp := query.NewQueryParams(query.WithType("MFA_ENROLL")) + output, resp, err := client.Policy.ListPolicies(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextPolicySet []*okta.Policy + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/policy_password.go b/providers/okta/policy_password.go new file mode 100644 index 000000000..7a70c8459 --- /dev/null +++ b/providers/okta/policy_password.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type PasswordPolicyGenerator struct { + OktaService +} + +func (g PasswordPolicyGenerator) createResources(passwordPolicyList []*okta.Policy) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, passwordPolicy := range passwordPolicyList { + resourceName := normalizeResourceName(passwordPolicy.Name) + resourceType := "okta_policy_password" + if passwordPolicy.Name == "Default Policy" { + resourceType = "okta_policy_password_default" + } + resources = append(resources, terraformutils.NewSimpleResource( + passwordPolicy.Id, + "policy_password_"+resourceName, + resourceType, + "okta", + []string{})) + } + return resources +} + +func (g *PasswordPolicyGenerator) InitResources() error { + var output []*okta.Policy + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, _ = getPasswordPolicies(ctx, client) + g.Resources = g.createResources(output) + return nil +} + +func getPasswordPolicies(ctx context.Context, client *okta.Client) ([]*okta.Policy, error) { + qp := query.NewQueryParams(query.WithType("PASSWORD")) + output, resp, err := client.Policy.ListPolicies(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextPolicySet []*okta.Policy + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/policy_rule_mfa.go b/providers/okta/policy_rule_mfa.go new file mode 100644 index 000000000..7c3067642 --- /dev/null +++ b/providers/okta/policy_rule_mfa.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/terraform-provider-okta/sdk" +) + +type MFAPolicyRuleGenerator struct { + OktaService +} + +func (g MFAPolicyRuleGenerator) createResources(mfaPolicyRuleList []sdk.PolicyRule, policyID string, policyName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, policyRule := range mfaPolicyRuleList { + resources = append(resources, terraformutils.NewResource( + policyRule.Id, + "policyrule_mfa_"+normalizeResourceName(policyName+"_"+policyRule.Name), + "okta_policy_rule_mfa", + "okta", + map[string]string{ + "policy_id": policyID, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *MFAPolicyRuleGenerator) InitResources() error { + var resources []terraformutils.Resource + + ctx, client, e := g.Client() + if e != nil { + return e + } + + mfaPolicies, err := getMFAPolicies(ctx, client) + if err != nil { + return err + } + + for _, policy := range mfaPolicies { + output, err := getMFAPolicyRules(g, policy.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, policy.Id, policy.Name)...) + } + + g.Resources = resources + return nil +} + +func getMFAPolicyRules(g *MFAPolicyRuleGenerator, policyID string) ([]sdk.PolicyRule, error) { + ctx, client, e := g.APISupplementClient() + if e != nil { + return nil, e + } + + output, resp, err := client.ListPolicyRules(ctx, policyID) + if err != nil { + return nil, e + } + + for resp.HasNextPage() { + var nextPolicySet []sdk.PolicyRule + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/policy_rule_password.go b/providers/okta/policy_rule_password.go new file mode 100644 index 000000000..0735264df --- /dev/null +++ b/providers/okta/policy_rule_password.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/terraform-provider-okta/sdk" +) + +type PasswordPolicyRuleGenerator struct { + OktaService +} + +func (g PasswordPolicyRuleGenerator) createResources(passwordPolicyRuleList []sdk.PolicyRule, policyID string, policyName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, policyRule := range passwordPolicyRuleList { + resources = append(resources, terraformutils.NewResource( + policyRule.Id, + "policyrule_password_"+normalizeResourceName(policyName+"_"+policyRule.Name), + "okta_policy_rule_password", + "okta", + map[string]string{ + "policy_id": policyID, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PasswordPolicyRuleGenerator) InitResources() error { + var resources []terraformutils.Resource + + ctx, client, e := g.Client() + if e != nil { + return e + } + + passwordPolicies, err := getPasswordPolicies(ctx, client) + if err != nil { + return err + } + + for _, policy := range passwordPolicies { + output, err := getPasswordPolicyRules(g, policy.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, policy.Id, policy.Name)...) + } + + g.Resources = resources + return nil +} + +func getPasswordPolicyRules(g *PasswordPolicyRuleGenerator, policyID string) ([]sdk.PolicyRule, error) { + ctx, client, e := g.APISupplementClient() + if e != nil { + return nil, e + } + + output, resp, err := client.ListPolicyRules(ctx, policyID) + if err != nil { + return nil, e + } + + for resp.HasNextPage() { + var nextPolicySet []sdk.PolicyRule + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/policy_rule_signon.go b/providers/okta/policy_rule_signon.go new file mode 100644 index 000000000..02c9c20f0 --- /dev/null +++ b/providers/okta/policy_rule_signon.go @@ -0,0 +1,90 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/terraform-provider-okta/sdk" +) + +type SignOnPolicyRuleGenerator struct { + OktaService +} + +func (g SignOnPolicyRuleGenerator) createResources(signOnPolicyRuleList []sdk.PolicyRule, policyID string, policyName string) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, policyRule := range signOnPolicyRuleList { + resources = append(resources, terraformutils.NewResource( + policyRule.Id, + "policyrule_signon_"+normalizeResourceName(policyName+"_"+policyRule.Name), + "okta_policy_rule_signon", + "okta", + map[string]string{ + "policy_id": policyID, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *SignOnPolicyRuleGenerator) InitResources() error { + var resources []terraformutils.Resource + + ctx, client, e := g.Client() + if e != nil { + return e + } + + signOnPolicies, err := getSignOnPolicies(ctx, client) + if err != nil { + return err + } + + for _, policy := range signOnPolicies { + output, err := getSignOnPolicyRules(g, policy.Id) + if err != nil { + return err + } + + resources = append(resources, g.createResources(output, policy.Id, policy.Name)...) + } + + g.Resources = resources + return nil +} + +func getSignOnPolicyRules(g *SignOnPolicyRuleGenerator, policyID string) ([]sdk.PolicyRule, error) { + ctx, client, e := g.APISupplementClient() + if e != nil { + return nil, e + } + + output, resp, err := client.ListPolicyRules(ctx, policyID) + if err != nil { + return nil, e + } + + for resp.HasNextPage() { + var nextPolicySet []sdk.PolicyRule + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/policy_signon.go b/providers/okta/policy_signon.go new file mode 100644 index 000000000..270e40e4c --- /dev/null +++ b/providers/okta/policy_signon.go @@ -0,0 +1,71 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" + "github.com/okta/okta-sdk-golang/v2/okta/query" +) + +type SignOnPolicyGenerator struct { + OktaService +} + +func (g SignOnPolicyGenerator) createResources(signOnPolicyList []*okta.Policy) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, signOnPolicy := range signOnPolicyList { + resourceName := normalizeResourceName(signOnPolicy.Name) + resourceType := "okta_policy_signon" + + resources = append(resources, terraformutils.NewSimpleResource( + signOnPolicy.Id, + "policy_signon_"+resourceName, + resourceType, + "okta", + []string{})) + } + return resources +} + +func (g *SignOnPolicyGenerator) InitResources() error { + var output []*okta.Policy + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, _ = getSignOnPolicies(ctx, client) + g.Resources = g.createResources(output) + return nil +} + +func getSignOnPolicies(ctx context.Context, client *okta.Client) ([]*okta.Policy, error) { + qp := query.NewQueryParams(query.WithType("OKTA_SIGN_ON")) + output, resp, err := client.Policy.ListPolicies(ctx, qp) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextPolicySet []*okta.Policy + resp, _ = resp.Next(ctx, &nextPolicySet) + output = append(output, nextPolicySet...) + } + + return output, nil +} diff --git a/providers/okta/template_sms.go b/providers/okta/template_sms.go new file mode 100644 index 000000000..0c7c2fe18 --- /dev/null +++ b/providers/okta/template_sms.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type SMSTemplateGenerator struct { + OktaService +} + +func (g SMSTemplateGenerator) createResources(smsTemplateList []*okta.SmsTemplate) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, smsTemplate := range smsTemplateList { + + resources = append(resources, terraformutils.NewSimpleResource( + smsTemplate.Id, + "template_sms_"+smsTemplate.Name, + "okta_template_sms", + "okta", + []string{})) + } + return resources +} + +func (g *SMSTemplateGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.SmsTemplate.ListSmsTemplates(ctx, nil) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextSmsTemplateSet []*okta.SmsTemplate + resp, _ = resp.Next(ctx, &nextSmsTemplateSet) + output = append(output, nextSmsTemplateSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/trusted_origin.go b/providers/okta/trusted_origin.go new file mode 100644 index 000000000..a0330e86c --- /dev/null +++ b/providers/okta/trusted_origin.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type TrustedOriginGenerator struct { + OktaService +} + +func (g TrustedOriginGenerator) createResources(trustedOriginList []*okta.TrustedOrigin) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, trustedOrigin := range trustedOriginList { + + resources = append(resources, terraformutils.NewSimpleResource( + trustedOrigin.Id, + "trusted_origin_"+trustedOrigin.Id, + "okta_trusted_origin", + "okta", + []string{})) + } + return resources +} + +func (g *TrustedOriginGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.TrustedOrigin.ListOrigins(ctx, nil) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextTrustedOriginSet []*okta.TrustedOrigin + resp, _ = resp.Next(ctx, &nextTrustedOriginSet) + output = append(output, nextTrustedOriginSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/user.go b/providers/okta/user.go new file mode 100644 index 000000000..5d4d784e6 --- /dev/null +++ b/providers/okta/user.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type UserGenerator struct { + OktaService +} + +func (g UserGenerator) createResources(userList []*okta.User) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, user := range userList { + + resources = append(resources, terraformutils.NewSimpleResource( + user.Id, + "user_"+user.Id, + "okta_user", + "okta", + []string{})) + } + return resources +} + +func (g *UserGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.User.ListUsers(ctx, nil) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextUserSet []*okta.User + resp, _ = resp.Next(ctx, &nextUserSet) + output = append(output, nextUserSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/okta/user_schema.go b/providers/okta/user_schema.go new file mode 100644 index 000000000..a003df7c7 --- /dev/null +++ b/providers/okta/user_schema.go @@ -0,0 +1,125 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "context" + "net/url" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type UserSchemaPropertyGenerator struct { + OktaService +} + +func (g UserSchemaPropertyGenerator) createResources(userSchema *okta.UserSchema, userTypeID string, userTypeName string) []terraformutils.Resource { + var resources []terraformutils.Resource + for index := range userSchema.Definitions.Custom.Properties { + resources = append(resources, terraformutils.NewResource( + index, + normalizeResourceName(userTypeName)+"_property_"+normalizeResourceName(index), + "okta_user_schema_property", + "okta", + map[string]string{ + "index": index, + "user_type": userTypeID, + }, + []string{}, + map[string]interface{}{}, + )) + } + + for index := range userSchema.Definitions.Base.Properties { + resources = append(resources, terraformutils.NewResource( + index, + normalizeResourceName(userTypeName)+"_property_"+normalizeResourceName(index), + "okta_user_base_schema_property", + "okta", + map[string]string{ + "index": index, + "user_type": userTypeID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resources +} + +func (g *UserSchemaPropertyGenerator) InitResources() error { + var resources []terraformutils.Resource + ctx, client, e := g.Client() + if e != nil { + return e + } + + userTypes, err := getUserTypes(ctx, client) + if err != nil { + return err + } + + for _, userType := range userTypes { + schemaID := getUserTypeSchemaID(userType) + if schemaID != "" { + schema, _, err := client.UserSchema.GetUserSchema(ctx, schemaID) + if err != nil { + return err + } + + userTypeID := "default" + if userType.Name != "user" { + userTypeID = userType.Id + } + + resources = append(resources, g.createResources(schema, userTypeID, userType.Name)...) + } + } + + g.Resources = resources + return nil +} + +func getUserTypes(ctx context.Context, client *okta.Client) ([]*okta.UserType, error) { + output, resp, err := client.UserType.ListUserTypes(ctx) + if err != nil { + return nil, err + } + + for resp.HasNextPage() { + var nextUserTypeSet []*okta.UserType + resp, _ = resp.Next(ctx, &nextUserTypeSet) + output = append(output, nextUserTypeSet...) + } + + return output, nil +} + +func getUserTypeSchemaID(ut *okta.UserType) string { + fm, ok := ut.Links.(map[string]interface{}) + if ok { + sm, ok := fm["schema"].(map[string]interface{}) + if ok { + href, ok := sm["href"].(string) + if ok { + u, _ := url.Parse(href) + return strings.TrimPrefix(u.EscapedPath(), "/api/v1/meta/schemas/user/") + } + } + } + return "" +} diff --git a/providers/okta/user_type.go b/providers/okta/user_type.go new file mode 100644 index 000000000..fb8c9ec28 --- /dev/null +++ b/providers/okta/user_type.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package okta + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +type UserTypeGenerator struct { + OktaService +} + +func (g UserTypeGenerator) createResources(userTypeList []*okta.UserType) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, userType := range userTypeList { + + resources = append(resources, terraformutils.NewSimpleResource( + userType.Id, + "usertype_"+userType.Name, + "okta_user_type", + "okta", + []string{})) + } + return resources +} + +func (g *UserTypeGenerator) InitResources() error { + ctx, client, e := g.Client() + if e != nil { + return e + } + + output, resp, err := client.UserType.ListUserTypes(ctx) + if err != nil { + return e + } + + for resp.HasNextPage() { + var nextUserTypeSet []*okta.UserType + resp, _ = resp.Next(ctx, &nextUserTypeSet) + output = append(output, nextUserTypeSet...) + } + + g.Resources = g.createResources(output) + return nil +} diff --git a/providers/opsgenie/opsgenie_provider.go b/providers/opsgenie/opsgenie_provider.go new file mode 100644 index 000000000..fa4f46284 --- /dev/null +++ b/providers/opsgenie/opsgenie_provider.go @@ -0,0 +1,70 @@ +package opsgenie + +import ( + "errors" + "os" + + "github.com/zclconf/go-cty/cty" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type OpsgenieProvider struct { //nolint + terraformutils.Provider + + APIKey string +} + +func (p *OpsgenieProvider) Init(args []string) error { + if apiKey := os.Getenv("OPSGENIE_API_KEY"); apiKey != "" { + p.APIKey = os.Getenv("OPSGENIE_API_KEY") + } + if args[0] != "" { + p.APIKey = args[0] + } + if p.APIKey == "" { + return errors.New("required API Key missing") + } + + return nil +} + +func (p *OpsgenieProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "api-key": p.APIKey, + }) + return nil +} + +func (p *OpsgenieProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "api_key": cty.StringVal(p.APIKey), + }) +} + +func (p *OpsgenieProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{} +} + +func (p *OpsgenieProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p *OpsgenieProvider) GetName() string { + return "opsgenie" +} + +func (p *OpsgenieProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "user": &UserGenerator{}, + "team": &TeamGenerator{}, + } +} diff --git a/providers/opsgenie/opsgenie_service.go b/providers/opsgenie/opsgenie_service.go new file mode 100644 index 000000000..3b02bf16f --- /dev/null +++ b/providers/opsgenie/opsgenie_service.go @@ -0,0 +1,21 @@ +package opsgenie + +import ( + "github.com/opsgenie/opsgenie-go-sdk-v2/client" + "github.com/opsgenie/opsgenie-go-sdk-v2/team" + "github.com/opsgenie/opsgenie-go-sdk-v2/user" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type OpsgenieService struct { //nolint + terraformutils.Service +} + +func (s *OpsgenieService) UserClient() (*user.Client, error) { + return user.NewClient(&client.Config{ApiKey: s.GetArgs()["api-key"].(string)}) +} + +func (s *OpsgenieService) TeamClient() (*team.Client, error) { + return team.NewClient(&client.Config{ApiKey: s.GetArgs()["api-key"].(string)}) +} diff --git a/providers/opsgenie/team.go b/providers/opsgenie/team.go new file mode 100644 index 000000000..f91ab9e6b --- /dev/null +++ b/providers/opsgenie/team.go @@ -0,0 +1,50 @@ +package opsgenie + +import ( + "context" + "time" + + "github.com/opsgenie/opsgenie-go-sdk-v2/team" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TeamGenerator struct { + OpsgenieService +} + +func (g *TeamGenerator) InitResources() error { + client, err := g.TeamClient() + if err != nil { + return err + } + + ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second) + defer cancelFunc() + + result, err := client.List(ctx, &team.ListTeamRequest{}) + if err != nil { + return err + } + + g.Resources = g.createResources(result.Teams) + return nil +} + +func (g *TeamGenerator) createResources(teams []team.ListedTeams) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, t := range teams { + resources = append(resources, terraformutils.NewResource( + t.Id, + t.Name, + "opsgenie_team", + g.ProviderName, + map[string]string{}, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} diff --git a/providers/opsgenie/user.go b/providers/opsgenie/user.go new file mode 100644 index 000000000..3a21c406d --- /dev/null +++ b/providers/opsgenie/user.go @@ -0,0 +1,68 @@ +package opsgenie + +import ( + "context" + "fmt" + "time" + + "github.com/opsgenie/opsgenie-go-sdk-v2/user" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type UserGenerator struct { + OpsgenieService +} + +func (g *UserGenerator) InitResources() error { + client, err := g.UserClient() + if err != nil { + return err + } + + limit := 50 + offset := 0 + + var users []user.User + + for { + result, err := func(limit, offset int) (*user.ListResult, error) { + ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second) + defer cancelFunc() + + return client.List(ctx, &user.ListRequest{Limit: limit, Offset: offset}) + }(limit, offset) + + if err != nil { + return err + } + + users = append(users, result.Users...) + offset += limit + + if offset >= result.TotalCount { + break + } + } + + g.Resources = g.createResources(users) + return nil +} + +func (g *UserGenerator) createResources(users []user.User) []terraformutils.Resource { + var resources []terraformutils.Resource + + for _, u := range users { + resources = append(resources, terraformutils.NewResource( + u.Id, + fmt.Sprintf("%s-%s", u.Id, u.Username), + "opsgenie_user", + g.ProviderName, + map[string]string{}, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} diff --git a/providers/pagerduty/business_service.go b/providers/pagerduty/business_service.go new file mode 100644 index 000000000..69be65ddd --- /dev/null +++ b/providers/pagerduty/business_service.go @@ -0,0 +1,63 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type BusinessServiceGenerator struct { + PagerDutyService +} + +func (g *BusinessServiceGenerator) createBusinessServiceResources(client *pagerduty.Client) error { + resp, _, err := client.BusinessServices.List() + if err != nil { + return err + } + + for _, service := range resp.BusinessServices { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + service.ID, + service.Name, + "pagerduty_business_service", + g.ProviderName, + []string{}, + )) + } + + return nil +} + +func (g *BusinessServiceGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createBusinessServiceResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/escalation_policy.go b/providers/pagerduty/escalation_policy.go new file mode 100644 index 000000000..3bd87bf35 --- /dev/null +++ b/providers/pagerduty/escalation_policy.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type EscalationPolicyGenerator struct { + PagerDutyService +} + +func (g *EscalationPolicyGenerator) createEscalationPolicyResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListEscalationPoliciesOptions{} + for { + options.Offset = offset + resp, _, err := client.EscalationPolicies.List(&options) + if err != nil { + return err + } + + for _, policy := range resp.EscalationPolicies { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + policy.ID, + policy.Name, + "pagerduty_escalation_policy", + g.ProviderName, + []string{}, + )) + } + + if !resp.More { + break + } + + offset += resp.Limit + } + return nil +} + +func (g *EscalationPolicyGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createEscalationPolicyResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/pagerduty_provider.go b/providers/pagerduty/pagerduty_provider.go new file mode 100644 index 000000000..7abd0ea64 --- /dev/null +++ b/providers/pagerduty/pagerduty_provider.go @@ -0,0 +1,89 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/zclconf/go-cty/cty" +) + +type PagerDutyProvider struct { //nolint + terraformutils.Provider + token string +} + +func (p *PagerDutyProvider) Init(args []string) error { + if token := os.Getenv("PAGERDUTY_TOKEN"); token != "" { + p.token = os.Getenv("PAGERDUTY_TOKEN") + } + if len(args) > 0 && args[0] != "" { + p.token = args[0] + } + return nil +} + +func (p *PagerDutyProvider) GetName() string { + return "pagerduty" +} + +func (p *PagerDutyProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "token": cty.StringVal(p.token), + }) +} + +func (p *PagerDutyProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "pagerduty": map[string]interface{}{ + "token": p.token, + }, + }, + } +} + +func (PagerDutyProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p *PagerDutyProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "business_service": &BusinessServiceGenerator{}, + "escalation_policy": &EscalationPolicyGenerator{}, + "ruleset": &RulesetGenerator{}, + "schedule": &ScheduleGenerator{}, + "service": &ServiceGenerator{}, + "team": &TeamGenerator{}, + "user": &UserGenerator{}, + } +} + +func (p *PagerDutyProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "token": p.token, + }) + return nil +} diff --git a/providers/pagerduty/pagerduty_service.go b/providers/pagerduty/pagerduty_service.go new file mode 100644 index 000000000..31bff9d19 --- /dev/null +++ b/providers/pagerduty/pagerduty_service.go @@ -0,0 +1,32 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type PagerDutyService struct { //nolint + terraformutils.Service +} + +func (s *PagerDutyService) Client() (*pagerduty.Client, error) { + client, err := pagerduty.NewClient(&pagerduty.Config{Token: s.GetArgs()["token"].(string)}) + if err != nil { + return nil, err + } + return client, nil +} diff --git a/providers/pagerduty/ruleset.go b/providers/pagerduty/ruleset.go new file mode 100644 index 000000000..3ba119f53 --- /dev/null +++ b/providers/pagerduty/ruleset.go @@ -0,0 +1,96 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type RulesetGenerator struct { + PagerDutyService +} + +func (g *RulesetGenerator) createRulesetResources(client *pagerduty.Client) error { + resp, _, err := client.Rulesets.List() + if err != nil { + return err + } + + for _, ruleset := range resp.Rulesets { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + ruleset.ID, + ruleset.Name, + "pagerduty_ruleset", + g.ProviderName, + []string{}, + )) + } + + return nil +} + +// golangci-lint says this function isn't used anywhere. Do we need it? Commenting it out to make the linter happy + +func (g *RulesetGenerator) createRulesetRuleResources(client *pagerduty.Client) error { + resp, _, err := client.Rulesets.List() + if err != nil { + return err + } + + for _, ruleset := range resp.Rulesets { + rules, _, err := client.Rulesets.ListRules(ruleset.ID) + if err != nil { + return err + } + + for _, rule := range rules.Rules { + g.Resources = append(g.Resources, terraformutils.NewResource( + rule.ID, + rule.ID, + "pagerduty_ruleset_rule", + g.ProviderName, + map[string]string{ + "ruleset": ruleset.ID, + }, + []string{}, + map[string]interface{}{}, + )) + } + } + + return nil +} + +func (g *RulesetGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createRulesetResources, + g.createRulesetRuleResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/schedule.go b/providers/pagerduty/schedule.go new file mode 100644 index 000000000..3b28da3aa --- /dev/null +++ b/providers/pagerduty/schedule.go @@ -0,0 +1,75 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type ScheduleGenerator struct { + PagerDutyService +} + +func (g *ScheduleGenerator) createScheduleResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListSchedulesOptions{} + for { + options.Offset = offset + resp, _, err := client.Schedules.List(&options) + if err != nil { + return err + } + + for _, schedule := range resp.Schedules { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + schedule.ID, + fmt.Sprintf("schedule_%s", schedule.Name), + "pagerduty_schedule", + g.ProviderName, + []string{}, + )) + } + if !resp.More { + break + } + + offset += resp.Limit + } + + return nil +} + +func (g *ScheduleGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createScheduleResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/service.go b/providers/pagerduty/service.go new file mode 100644 index 000000000..e5b887bd1 --- /dev/null +++ b/providers/pagerduty/service.go @@ -0,0 +1,118 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type ServiceGenerator struct { + PagerDutyService +} + +func (g *ServiceGenerator) createServiceResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListServicesOptions{} + for { + options.Offset = offset + resp, _, err := client.Services.List(&options) + if err != nil { + return err + } + + for _, service := range resp.Services { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + service.ID, + fmt.Sprintf("service_%s", service.Name), + "pagerduty_service", + g.ProviderName, + []string{}, + )) + } + + if !resp.More { + break + } + offset += resp.Limit + } + + return nil +} + +func (g *ServiceGenerator) createServiceEventRuleResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListServicesOptions{} + optionsEventRules := pagerduty.ListServiceEventRuleOptions{} + for { + options.Offset = offset + optionsEventRules.Offset = offset + resp, _, err := client.Services.List(&options) + if err != nil { + return err + } + + for _, service := range resp.Services { + rules, _, err := client.Services.ListEventRules(service.ID, &optionsEventRules) + + if err != nil { + return err + } + + for _, rule := range rules.EventRules { + g.Resources = append(g.Resources, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("%s_%s", service.Name, rule.ID), + "pagerduty_service_event_rule", + g.ProviderName, + map[string]string{ + "service": service.ID, + }, + []string{}, + map[string]interface{}{}, + )) + } + } + + if !resp.More { + break + } + offset += resp.Limit + } + return nil +} + +func (g *ServiceGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createServiceResources, + g.createServiceEventRuleResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/team.go b/providers/pagerduty/team.go new file mode 100644 index 000000000..fab6ffe92 --- /dev/null +++ b/providers/pagerduty/team.go @@ -0,0 +1,116 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type TeamGenerator struct { + PagerDutyService +} + +func (g *TeamGenerator) createTeamResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListTeamsOptions{} + for { + options.Offset = offset + resp, _, err := client.Teams.List(&options) + if err != nil { + return err + } + + for _, team := range resp.Teams { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + team.ID, + fmt.Sprintf("Team_%s", team.Name), + "pagerduty_team", + g.ProviderName, + []string{}, + )) + } + if !resp.More { + break + } + + offset += resp.Limit + } + + return nil +} + +func (g *TeamGenerator) createTeamMembershipResources(client *pagerduty.Client) error { + var teamOffset = 0 + teamOptions := pagerduty.ListTeamsOptions{} + + for { + teamOptions.Offset = teamOffset + resp, _, err := client.Teams.List(&teamOptions) + if err != nil { + return err + } + + memberOptions := pagerduty.GetMembersOptions{} + for _, team := range resp.Teams { + members, _, err := client.Teams.GetMembers(team.ID, &memberOptions) + + if err != nil { + return err + } + + for _, member := range members.Members { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + fmt.Sprintf("%s:%s", member.User.ID, team.ID), + fmt.Sprintf("%s_%s", member.User.ID, team.Name), + "pagerduty_team_membership", + g.ProviderName, + []string{}, + )) + } + } + + if !resp.More { + break + } + + teamOffset += resp.Limit + } + + return nil +} + +func (g *TeamGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createTeamResources, + g.createTeamMembershipResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/pagerduty/user.go b/providers/pagerduty/user.go new file mode 100644 index 000000000..dce4b3921 --- /dev/null +++ b/providers/pagerduty/user.go @@ -0,0 +1,76 @@ +// Copyright 2019 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pagerduty + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + pagerduty "github.com/heimweh/go-pagerduty/pagerduty" +) + +type UserGenerator struct { + PagerDutyService +} + +func (g *UserGenerator) createUserResources(client *pagerduty.Client) error { + var offset = 0 + options := pagerduty.ListUsersOptions{} + for { + options.Offset = offset + resp, _, err := client.Users.List(&options) + if err != nil { + return err + } + + for _, user := range resp.Users { + g.Resources = append(g.Resources, terraformutils.NewSimpleResource( + user.ID, + fmt.Sprintf("user_%s", user.ID), + "pagerduty_user", + g.ProviderName, + []string{}, + )) + } + + if !resp.More { + break + } + + offset += resp.Limit + } + + return nil +} + +func (g *UserGenerator) InitResources() error { + client, err := g.Client() + if err != nil { + return err + } + + funcs := []func(*pagerduty.Client) error{ + g.createUserResources, + } + + for _, f := range funcs { + err := f(client) + if err != nil { + return err + } + } + + return nil +} diff --git a/providers/panos/firewall_device_config.go b/providers/panos/firewall_device_config.go new file mode 100644 index 000000000..03298fbfb --- /dev/null +++ b/providers/panos/firewall_device_config.go @@ -0,0 +1,112 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" +) + +type FirewallDeviceConfigGenerator struct { + PanosService +} + +func (g *FirewallDeviceConfigGenerator) createResourcesFromList(o getGeneric, idPrefix, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := idPrefix + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(r), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *FirewallDeviceConfigGenerator) createGeneralSettingsResource(hostname string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + hostname, + normalizeResourceName(hostname), + "panos_general_settings", + "panos", + []string{}, + ) +} + +func (g *FirewallDeviceConfigGenerator) createTelemetryResource(ipAddress, hostname string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + ipAddress, + normalizeResourceName(hostname), + "panos_telemetry", + "panos", + []string{}, + ) +} + +func (g *FirewallDeviceConfigGenerator) createEmailServerProfileResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Device.EmailServerProfile, []string{g.vsys}}, + g.vsys+":", "panos_email_server_profile", + ) +} + +func (g *FirewallDeviceConfigGenerator) createHTTPServerProfileResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Device.HttpServerProfile, []string{g.vsys}}, + g.vsys+":", "panos_http_server_profile", + ) +} + +func (g *FirewallDeviceConfigGenerator) createSNMPTrapServerProfileResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Device.SnmpServerProfile, []string{g.vsys}}, + g.vsys+":", "panos_snmptrap_server_profile", + ) +} + +func (g *FirewallDeviceConfigGenerator) createSyslogServerProfileResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Device.SyslogServerProfile, []string{g.vsys}}, + g.vsys+":", "panos_syslog_server_profile", + ) +} + +func (g *FirewallDeviceConfigGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + if g.vsys == "vsys1" { + g.vsys = "shared" + } + + generalConfig, err := g.client.(*pango.Firewall).Device.GeneralSettings.Get() + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createGeneralSettingsResource(generalConfig.Hostname)) + g.Resources = append(g.Resources, g.createTelemetryResource(generalConfig.IpAddress, generalConfig.Hostname)) + g.Resources = append(g.Resources, g.createEmailServerProfileResources()...) + g.Resources = append(g.Resources, g.createHTTPServerProfileResources()...) + g.Resources = append(g.Resources, g.createSNMPTrapServerProfileResources()...) + g.Resources = append(g.Resources, g.createSyslogServerProfileResources()...) + + return nil +} diff --git a/providers/panos/firewall_networking.go b/providers/panos/firewall_networking.go new file mode 100644 index 000000000..5a66465c7 --- /dev/null +++ b/providers/panos/firewall_networking.go @@ -0,0 +1,813 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "encoding/base64" + "fmt" + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/netw/interface/eth" + "github.com/PaloAltoNetworks/pango/netw/interface/subinterface/layer2" + "github.com/PaloAltoNetworks/pango/netw/interface/subinterface/layer3" + "github.com/PaloAltoNetworks/pango/util" +) + +type FirewallNetworkingGenerator struct { + PanosService +} + +func (g *FirewallNetworkingGenerator) createResourcesFromList(o getGeneric, idPrefix string, useIDForResourceName bool, terraformResourceName string, checkIfIsVsys bool, checkType string) (resources []terraformutils.Resource) { + var l []string + var err error + + switch f := o.i.(type) { + case getListWithoutArg: + l, err = f.GetList() + case getListWithOneArg: + l, err = f.GetList(o.params[0]) + case getListWithTwoArgs: + l, err = f.GetList(o.params[0], o.params[1]) + case getListWithThreeArgs: + l, err = f.GetList(o.params[0], o.params[1], o.params[2]) + default: + err = fmt.Errorf("not supported") + } + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + if checkIfIsVsys { + rv, err := g.client.(*pango.Firewall).IsImported(checkType, "", "", g.vsys, r) + if err != nil || !rv { + continue + } + } + + id := idPrefix + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(func() string { + if useIDForResourceName { + return id + } + + return r + }()), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createAggregateInterfaceResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.AggregateInterface.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, aggregateInterface := range l { + rv, err := g.client.(*pango.Firewall).IsImported(util.InterfaceImport, "", "", g.vsys, aggregateInterface) + if err != nil || !rv { + continue + } + + id := g.vsys + ":" + aggregateInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(aggregateInterface), + "panos_aggregate_interface", + "panos", + []string{}, + )) + + e, err := g.client.(*pango.Firewall).Network.AggregateInterface.Get(aggregateInterface) + if err != nil { + continue + } + + if e.Mode == eth.ModeLayer2 || e.Mode == eth.ModeVirtualWire { + g.Resources = append(g.Resources, g.createLayer2SubInterfaceResources(layer2.AggregateInterface, aggregateInterface, e.Mode)...) + } + + if e.Mode == eth.ModeLayer3 { + g.Resources = append(g.Resources, g.createLayer3SubInterfaceResources(layer3.AggregateInterface, aggregateInterface)...) + } + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createBFDProfileResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BfdProfile, []string{}}, + "", false, "panos_bfd_profile", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPResource(virtualRouter string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + virtualRouter, + normalizeResourceName(virtualRouter), + "panos_bgp", + "panos", + []string{}, + ) +} + +func (g *FirewallNetworkingGenerator) createBGPAggregateResources(virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.BgpAggregate.GetList(virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpAggregate := range l { + id := virtualRouter + ":" + bgpAggregate + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_bgp_aggregate", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPAggregateAdvertiseFilterResources(virtualRouter, bgpAggregate)...) + resources = append(resources, g.createBGPAggregateSuppressFilterResources(virtualRouter, bgpAggregate)...) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createBGPAggregateAdvertiseFilterResources(virtualRouter, bgpAggregate string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpAggAdvertiseFilter, []string{virtualRouter, bgpAggregate}}, + virtualRouter+":"+bgpAggregate+":", true, "panos_bgp_aggregate_advertise_filter", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPAggregateSuppressFilterResources(virtualRouter, bgpAggregate string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpAggSuppressFilter, []string{virtualRouter, bgpAggregate}}, + virtualRouter+":"+bgpAggregate+":", true, "panos_bgp_aggregate_suppress_filter", false, "", + ) +} + +// The secret argument will contain "(incorrect)", not the real value +func (g *FirewallNetworkingGenerator) createBGPAuthProfileResources(virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpAuthProfile, []string{virtualRouter}}, + virtualRouter+":", true, "panos_bgp_auth_profile", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPConditionalAdvertisementResources(virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.BgpConditionalAdv.GetList(virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpConditionalAdv := range l { + id := virtualRouter + ":" + bgpConditionalAdv + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_bgp_conditional_adv", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPConditionalAdvertisementAdvertiseFilterResources(virtualRouter, bgpConditionalAdv)...) + resources = append(resources, g.createBGPConditionalAdvertisementNonExistFilterResources(virtualRouter, bgpConditionalAdv)...) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createBGPConditionalAdvertisementAdvertiseFilterResources(virtualRouter, bgpConditionalAdv string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpConAdvAdvertiseFilter, []string{virtualRouter, bgpConditionalAdv}}, + virtualRouter+":"+bgpConditionalAdv+":", true, "panos_bgp_conditional_adv_advertise_filter", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPConditionalAdvertisementNonExistFilterResources(virtualRouter, bgpConditionalAdv string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpConAdvNonExistFilter, []string{virtualRouter, bgpConditionalAdv}}, + virtualRouter+":"+bgpConditionalAdv+":", true, "panos_bgp_conditional_adv_non_exist_filter", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPDampeningProfileResources(virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpDampeningProfile, []string{virtualRouter}}, + virtualRouter+":", true, "panos_bgp_dampening_profile", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPRuleGroupResourcesFromList(o getGeneric, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + var positionReference string + id := o.params[0] + ":" + strconv.Itoa(util.MoveTop) + "::" + + for k, r := range l { + if k > 0 { + id = o.params[0] + ":" + strconv.Itoa(util.MoveAfter) + ":" + positionReference + ":" + } + + id += base64.StdEncoding.EncodeToString([]byte(r)) + positionReference = r + + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(r), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createBGPExportRuleGroupResources(virtualRouter string) []terraformutils.Resource { + return g.createBGPRuleGroupResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpExport, []string{virtualRouter}}, + "panos_bgp_export_rule_group", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPImportRuleGroupResources(virtualRouter string) []terraformutils.Resource { + return g.createBGPRuleGroupResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpImport, []string{virtualRouter}}, + "panos_bgp_import_rule_group", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPPeerGroupResources(virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.BgpPeerGroup.GetList(virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpPeerGroup := range l { + id := virtualRouter + ":" + bgpPeerGroup + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_bgp_peer_group", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPPeerResources(virtualRouter, bgpPeerGroup)...) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createBGPPeerResources(virtualRouter, bgpPeerGroup string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpPeer, []string{virtualRouter, bgpPeerGroup}}, + virtualRouter+":"+bgpPeerGroup+":", true, "panos_bgp_peer", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createBGPRedistResources(virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.BgpRedistRule, []string{virtualRouter}}, + virtualRouter+":", true, "panos_bgp_redist_rule", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createEthernetInterfaceResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.EthernetInterface.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, ethernetInterface := range l { + rv, err := g.client.(*pango.Firewall).IsImported(util.InterfaceImport, "", "", g.vsys, ethernetInterface) + if err != nil || !rv { + continue + } + + id := g.vsys + ":" + ethernetInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(ethernetInterface), + "panos_ethernet_interface", + "panos", + []string{}, + )) + + e, err := g.client.(*pango.Firewall).Network.EthernetInterface.Get(ethernetInterface) + if err != nil { + continue + } + + if e.Mode == eth.ModeLayer2 || e.Mode == eth.ModeVirtualWire { + g.Resources = append(g.Resources, g.createLayer2SubInterfaceResources(layer2.EthernetInterface, ethernetInterface, e.Mode)...) + } + + if e.Mode == eth.ModeLayer3 { + g.Resources = append(g.Resources, g.createLayer3SubInterfaceResources(layer3.EthernetInterface, ethernetInterface)...) + } + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createGRETunnelResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.GreTunnel, []string{}}, + "", false, "panos_gre_tunnel", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createIKECryptoProfileResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.IkeCryptoProfile.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, ikeCryptoProfile := range l { + resources = append(resources, terraformutils.NewResource( + ikeCryptoProfile, + normalizeResourceName(ikeCryptoProfile), + "panos_ike_crypto_profile", + "panos", + map[string]string{ + "name": ikeCryptoProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createIKEGatewayResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.IkeGateway.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, ikeGateway := range l { + resources = append(resources, terraformutils.NewResource( + ikeGateway, + normalizeResourceName(ikeGateway), + "panos_ike_gateway", + "panos", + map[string]string{ + "name": ikeGateway, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createIPSECCryptoProfileResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.IpsecCryptoProfile.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, ipsecCryptoProfile := range l { + resources = append(resources, terraformutils.NewResource( + ipsecCryptoProfile, + normalizeResourceName(ipsecCryptoProfile), + "panos_ipsec_crypto_profile", + "panos", + map[string]string{ + "name": ipsecCryptoProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createIPSECTunnelProxyIDIPv4Resources(ipsecTunnel string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.IpsecTunnelProxyId, []string{ipsecTunnel}}, + ipsecTunnel+":", false, "panos_ipsec_tunnel_proxy_id_ipv4", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createIPSECTunnelResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.IpsecTunnel.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, ipsecTunnel := range l { + resources = append(resources, terraformutils.NewSimpleResource( + ipsecTunnel, + normalizeResourceName(ipsecTunnel), + "panos_ipsec_tunnel", + "panos", + []string{}, + )) + + resources = append(resources, g.createIPSECTunnelProxyIDIPv4Resources(ipsecTunnel)...) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createLayer2SubInterfaceResources(interfaceType, parentInterface, parentMode string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.Layer2Subinterface, []string{interfaceType, parentInterface, parentMode}}, + interfaceType+":"+parentInterface+":"+parentMode+":"+g.vsys+":", false, "panos_layer2_subinterface", true, util.InterfaceImport, + ) +} + +func (g *FirewallNetworkingGenerator) createLayer3SubInterfaceResources(interfaceType, parentInterface string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.Layer3Subinterface, []string{interfaceType, parentInterface}}, + interfaceType+":"+parentInterface+":"+g.vsys+":", false, "panos_layer3_subinterface", true, util.InterfaceImport, + ) +} + +func (g *FirewallNetworkingGenerator) createLoopbackInterfaceResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.LoopbackInterface, []string{}}, + g.vsys+":", false, "panos_loopback_interface", true, util.InterfaceImport, + ) +} + +func (g *FirewallNetworkingGenerator) createManagementProfileResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.ManagementProfile.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, managementProfile := range l { + resources = append(resources, terraformutils.NewResource( + managementProfile, + normalizeResourceName(managementProfile), + "panos_management_profile", + "panos", + map[string]string{ + "name": managementProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createMonitorProfileResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.MonitorProfile, []string{}}, + "", false, "panos_monitor_profile", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createRedistributionProfileResources(virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.RedistributionProfile, []string{virtualRouter}}, + virtualRouter+":", true, "panos_redistribution_profile_ipv4", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createStaticRouteIpv4Resources(virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.StaticRoute, []string{virtualRouter}}, + virtualRouter+":", true, "panos_static_route_ipv4", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createTunnelInterfaceResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.TunnelInterface, []string{}}, + g.vsys+":", false, "panos_tunnel_interface", true, util.InterfaceImport, + ) +} + +func (g *FirewallNetworkingGenerator) createVirtualRouterResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Network.VirtualRouter.GetList() + if err != nil { + return []terraformutils.Resource{} + } + + for _, virtualRouter := range l { + // TODO: doesn't work!!? + // rv, err := g.client.(*pango.Firewall).IsImported(util.VirtualRouterImport, "", "", g.vsys, virtualRouter) + // if err != nil || !rv { + // continue + // } + + id := g.vsys + ":" + virtualRouter + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(virtualRouter), + "panos_virtual_router", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPResource(virtualRouter)) + resources = append(resources, g.createBGPAggregateResources(virtualRouter)...) + resources = append(resources, g.createBGPAuthProfileResources(virtualRouter)...) + resources = append(resources, g.createBGPConditionalAdvertisementResources(virtualRouter)...) + resources = append(resources, g.createBGPDampeningProfileResources(virtualRouter)...) + resources = append(resources, g.createBGPExportRuleGroupResources(virtualRouter)...) + resources = append(resources, g.createBGPImportRuleGroupResources(virtualRouter)...) + resources = append(resources, g.createBGPPeerGroupResources(virtualRouter)...) + resources = append(resources, g.createBGPRedistResources(virtualRouter)...) + resources = append(resources, g.createRedistributionProfileResources(virtualRouter)...) + resources = append(resources, g.createStaticRouteIpv4Resources(virtualRouter)...) + } + + return resources +} + +func (g *FirewallNetworkingGenerator) createVlanResources() []terraformutils.Resource { + // TODO: should activate check with util.VlanImport, but doesn't work? + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.Vlan, []string{}}, + g.vsys+":", false, "panos_vlan", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) createVlanInterfaceResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.VlanInterface, []string{}}, + g.vsys+":", false, "panos_vlan_interface", true, util.InterfaceImport, + ) +} + +func (g *FirewallNetworkingGenerator) createZoneResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Network.Zone, []string{g.vsys}}, + g.vsys+":", false, "panos_zone", false, "", + ) +} + +func (g *FirewallNetworkingGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + g.Resources = append(g.Resources, g.createAggregateInterfaceResources()...) + g.Resources = append(g.Resources, g.createBFDProfileResources()...) + g.Resources = append(g.Resources, g.createEthernetInterfaceResources()...) + g.Resources = append(g.Resources, g.createGRETunnelResources()...) + g.Resources = append(g.Resources, g.createIKECryptoProfileResources()...) + g.Resources = append(g.Resources, g.createIKEGatewayResources()...) + g.Resources = append(g.Resources, g.createIPSECCryptoProfileResources()...) + g.Resources = append(g.Resources, g.createIPSECTunnelResources()...) + g.Resources = append(g.Resources, g.createLoopbackInterfaceResources()...) + g.Resources = append(g.Resources, g.createManagementProfileResources()...) + g.Resources = append(g.Resources, g.createMonitorProfileResources()...) + g.Resources = append(g.Resources, g.createTunnelInterfaceResources()...) + g.Resources = append(g.Resources, g.createVirtualRouterResources()...) + g.Resources = append(g.Resources, g.createVlanResources()...) + g.Resources = append(g.Resources, g.createVlanInterfaceResources()...) + g.Resources = append(g.Resources, g.createZoneResources()...) + + return nil +} + +func (g *FirewallNetworkingGenerator) PostConvertHook() error { + mapInterfaceNames := map[string]string{} + mapInterfaceModes := map[string]string{} + mapIKECryptoProfileNames := map[string]string{} + mapIKEGatewayNames := map[string]string{} + mapIPSECCryptoProfileNames := map[string]string{} + + for _, r := range g.Resources { + if _, ok := r.Item["name"]; ok { + if r.InstanceInfo.Type == "panos_aggregate_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + mapInterfaceModes[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".mode}" + } + + if r.InstanceInfo.Type == "panos_ethernet_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + mapInterfaceModes[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".mode}" + } + + if r.InstanceInfo.Type == "panos_layer2_subinterface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_layer3_subinterface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_loopback_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_tunnel_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_vlan_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_ike_crypto_profile" { + mapIKECryptoProfileNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_ike_gateway" { + mapIKEGatewayNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_ipsec_crypto_profile" { + mapIPSECCryptoProfileNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + } + } + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_bgp" || + r.InstanceInfo.Type == "panos_redistribution_profile_ipv4" || + r.InstanceInfo.Type == "panos_static_route_ipv4" { + if _, ok := r.Item["virtual_router"]; ok { + r.Item["virtual_router"] = "${panos_virtual_router." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_bgp_aggregate" || + r.InstanceInfo.Type == "panos_bgp_auth_profile" || + r.InstanceInfo.Type == "panos_bgp_conditional_adv" || + r.InstanceInfo.Type == "panos_bgp_dampening_profile" || + r.InstanceInfo.Type == "panos_bgp_export_rule_group" || + r.InstanceInfo.Type == "panos_bgp_import_rule_group" || + r.InstanceInfo.Type == "panos_bgp_peer_group" || + r.InstanceInfo.Type == "panos_bgp_redist_rule" { + if _, ok := r.Item["virtual_router"]; ok { + r.Item["virtual_router"] = "${panos_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + } + + if r.InstanceInfo.Type == "panos_bgp_aggregate_advertise_filter" || + r.InstanceInfo.Type == "panos_bgp_aggregate_suppress_filter" { + if _, ok := r.Item["virtual_router"]; ok { + r.Item["virtual_router"] = "${panos_bgp_aggregate." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + if _, ok := r.Item["bgp_aggregate"]; ok { + r.Item["bgp_aggregate"] = "${panos_bgp_aggregate." + normalizeResourceName(r.Item["bgp_aggregate"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_bgp_peer" { + if _, ok := r.Item["virtual_router"]; ok { + r.Item["virtual_router"] = "${panos_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + r.Item["peer_as"] = "${panos_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".as_number}" + } + } + + if r.InstanceInfo.Type == "panos_bgp_conditional_adv_advertise_filter" || + r.InstanceInfo.Type == "panos_bgp_conditional_adv_non_exist_filter" { + if _, ok := r.Item["virtual_router"]; ok { + r.Item["virtual_router"] = "${panos_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + if _, ok := r.Item["panos_bgp_conditional_adv"]; ok { + r.Item["bgp_conditional_adv"] = "${panos_bgp_conditional_adv." + normalizeResourceName(r.Item["panos_bgp_conditional_adv"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_gre_tunnel" { + if mapExists(mapInterfaceNames, r.Item, "interface") { + r.Item["interface"] = mapInterfaceNames[r.Item["interface"].(string)] + } + if mapExists(mapInterfaceNames, r.Item, "tunnel_interface") { + r.Item["tunnel_interface"] = mapInterfaceNames[r.Item["tunnel_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_ike_gateway" { + if mapExists(mapIKECryptoProfileNames, r.Item, "ikev1_crypto_profile") { + r.Item["ikev1_crypto_profile"] = mapIKECryptoProfileNames[r.Item["ikev1_crypto_profile"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_ipsec_tunnel" { + if mapExists(mapInterfaceNames, r.Item, "tunnel_interface") { + r.Item["tunnel_interface"] = mapInterfaceNames[r.Item["tunnel_interface"].(string)] + } + if mapExists(mapIKEGatewayNames, r.Item, "ak_ike_gateway") { + r.Item["ak_ike_gateway"] = mapIKEGatewayNames[r.Item["ak_ike_gateway"].(string)] + } + if mapExists(mapIPSECCryptoProfileNames, r.Item, "ak_ipsec_crypto_profile") { + r.Item["ak_ipsec_crypto_profile"] = mapIPSECCryptoProfileNames[r.Item["ak_ipsec_crypto_profile"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_ipsec_tunnel_proxy_id_ipv4" { + if mapExists(mapInterfaceNames, r.Item, "ipsec_tunnel") { + r.Item["ipsec_tunnel"] = mapInterfaceNames[r.Item["ipsec_tunnel"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_layer2_subinterface" { + if mapExists(mapInterfaceModes, r.Item, "parent_interface") { + r.Item["parent_mode"] = mapInterfaceModes[r.Item["parent_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_layer2_subinterface" || + r.InstanceInfo.Type == "panos_layer3_subinterface" { + if mapExists(mapInterfaceNames, r.Item, "parent_interface") { + r.Item["parent_interface"] = mapInterfaceNames[r.Item["parent_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_virtual_router" { + if r.Item["ospfv3_ext_dist"].(string) == "0" { + r.Item["ospfv3_ext_dist"] = "110" + } + + if r.Item["ebgp_dist"].(string) == "0" { + r.Item["ebgp_dist"] = "20" + } + + if r.Item["rip_dist"].(string) == "0" { + r.Item["rip_dist"] = "120" + } + + if r.Item["ibgp_dist"].(string) == "0" { + r.Item["ibgp_dist"] = "200" + } + + if r.Item["static_dist"].(string) == "0" { + r.Item["static_dist"] = "10" + } + + if r.Item["ospf_int_dist"].(string) == "0" { + r.Item["ospf_int_dist"] = "30" + } + + if r.Item["static_ipv6_dist"].(string) == "0" { + r.Item["static_ipv6_dist"] = "10" + } + + if r.Item["ospf_ext_dist"].(string) == "0" { + r.Item["ospf_ext_dist"] = "110" + } + + if r.Item["ospfv3_int_dist"].(string) == "0" { + r.Item["ospfv3_int_dist"] = "30" + } + } + + if r.InstanceInfo.Type == "panos_virtual_router" || + r.InstanceInfo.Type == "panos_zone" { + if _, ok := r.Item["interfaces"]; ok { + interfaces := make([]string, len(r.Item["interfaces"].([]interface{}))) + for k, eth := range r.Item["interfaces"].([]interface{}) { + if name, ok2 := mapInterfaceNames[eth.(string)]; ok2 { + interfaces[k] = name + continue + } + interfaces[k] = eth.(string) + } + + r.Item["interfaces"] = interfaces + } + } + + if r.InstanceInfo.Type == "panos_vlan" { + if mapExists(mapInterfaceNames, r.Item, "vlan_interface") { + r.Item["vlan_interface"] = mapInterfaceNames[r.Item["vlan_interface"].(string)] + } + } + } + + return nil +} diff --git a/providers/panos/firewall_objects.go b/providers/panos/firewall_objects.go new file mode 100644 index 000000000..7d5eff664 --- /dev/null +++ b/providers/panos/firewall_objects.go @@ -0,0 +1,325 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" +) + +type FirewallObjectsGenerator struct { + PanosService +} + +func (g *FirewallObjectsGenerator) createResourcesFromList(o getGeneric, idPrefix string, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := idPrefix + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(r), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *FirewallObjectsGenerator) createResourcesFromListWithVsys(o getGeneric, idPrefix string, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := idPrefix + r + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(r), + terraformResourceName, + "panos", + map[string]string{ + "vsys": g.vsys, + "device_group": "shared", + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *FirewallObjectsGenerator) createAddressGroupResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.AddressGroup, []string{g.vsys}}, + g.vsys+":", "panos_address_group", + ) +} + +func (g *FirewallObjectsGenerator) createAdministrativeTagResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.Tags, []string{g.vsys}}, + g.vsys+":", "panos_administrative_tag", + ) +} + +func (g *FirewallObjectsGenerator) createApplicationGroupResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.AppGroup, []string{g.vsys}}, + g.vsys+":", "panos_application_group", + ) +} + +func (g *FirewallObjectsGenerator) createApplicationObjectResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Firewall).Objects.Application.GetList(g.vsys) + if err != nil { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := g.vsys + ":" + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(r), + "panos_application_object", + "panos", + []string{}, + )) + + // TODO: fix + // resources = append(resources, g.createApplicationSignatureResources(r)...) + } + + return resources +} + +// func (g *FirewallObjectsGenerator) createApplicationSignatureResources(applicationObject string) []terraformutils.Resource { +// return g.createResourcesFromList( +// getGeneric{g.client.(*pango.Firewall).Objects.AppSignature, []string{g.vsys, applicationObject}}, +// g.vsys+":"+applicationObject+":", "panos_application_signature", +// ) +// } + +func (g *FirewallObjectsGenerator) createEDLResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.Edl, []string{g.vsys}}, + g.vsys+":", "panos_edl", + ) +} + +func (g *FirewallObjectsGenerator) createLogForwardingResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.LogForwardingProfile, []string{g.vsys}}, + g.vsys+":", "panos_log_forwarding_profile", + ) +} + +func (g *FirewallObjectsGenerator) createServiceGroupResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.ServiceGroup, []string{g.vsys}}, + g.vsys+":", "panos_service_group", + ) +} + +func (g *FirewallObjectsGenerator) createServiceObjectResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.Services, []string{g.vsys}}, + g.vsys+":", "panos_service_object", + ) +} + +func (g *FirewallObjectsGenerator) createAddressObjectResources() []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Firewall).Objects.Address, []string{g.vsys}}, + g.vsys+":", "panos_address_object", + ) +} + +func (g *FirewallObjectsGenerator) createAntiSpywareSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.AntiSpywareProfile, []string{g.vsys}}, + g.vsys+":", "panos_anti_spyware_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createAntivirusSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.AntivirusProfile, []string{g.vsys}}, + g.vsys+":", "panos_antivirus_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createCustomDataPatternObjectResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.DataPattern, []string{g.vsys}}, + g.vsys+":", "panos_custom_data_pattern_object", + ) +} + +func (g *FirewallObjectsGenerator) createDataFilteringSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.DataFilteringProfile, []string{g.vsys}}, + g.vsys+":", "panos_data_filtering_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createDOSProtectionProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.DosProtectionProfile, []string{g.vsys}}, + g.vsys+":", "panos_dos_protection_profile", + ) +} + +func (g *FirewallObjectsGenerator) createDynamicUserGroupResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.DynamicUserGroup, []string{g.vsys}}, + g.vsys+":", "panos_dynamic_user_group", + ) +} + +func (g *FirewallObjectsGenerator) createFileBlockingSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.FileBlockingProfile, []string{g.vsys}}, + g.vsys+":", "panos_file_blocking_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createURLFilteringSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.UrlFilteringProfile, []string{g.vsys}}, + g.vsys+":", "panos_url_filtering_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createVulnerabilitySecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.VulnerabilityProfile, []string{g.vsys}}, + g.vsys+":", "panos_vulnerability_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) createWildfireAnalysisSecurityProfileResources() []terraformutils.Resource { + return g.createResourcesFromListWithVsys( + getGeneric{g.client.(*pango.Firewall).Objects.WildfireAnalysisProfile, []string{g.vsys}}, + g.vsys+":", "panos_wildfire_analysis_security_profile", + ) +} + +func (g *FirewallObjectsGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + g.Resources = append(g.Resources, g.createAddressGroupResources()...) + g.Resources = append(g.Resources, g.createAdministrativeTagResources()...) + g.Resources = append(g.Resources, g.createApplicationGroupResources()...) + g.Resources = append(g.Resources, g.createApplicationObjectResources()...) + g.Resources = append(g.Resources, g.createEDLResources()...) + g.Resources = append(g.Resources, g.createLogForwardingResources()...) + g.Resources = append(g.Resources, g.createServiceGroupResources()...) + g.Resources = append(g.Resources, g.createServiceObjectResources()...) + + g.Resources = append(g.Resources, g.createAddressObjectResources()...) + g.Resources = append(g.Resources, g.createAntiSpywareSecurityProfileResources()...) + g.Resources = append(g.Resources, g.createAntivirusSecurityProfileResources()...) + g.Resources = append(g.Resources, g.createCustomDataPatternObjectResources()...) + g.Resources = append(g.Resources, g.createDataFilteringSecurityProfileResources()...) + g.Resources = append(g.Resources, g.createDOSProtectionProfileResources()...) + g.Resources = append(g.Resources, g.createDynamicUserGroupResources()...) + g.Resources = append(g.Resources, g.createFileBlockingSecurityProfileResources()...) + g.Resources = append(g.Resources, g.createURLFilteringSecurityProfileResources()...) + g.Resources = append(g.Resources, g.createVulnerabilitySecurityProfileResources()...) + g.Resources = append(g.Resources, g.createWildfireAnalysisSecurityProfileResources()...) + + return nil +} + +func (g *FirewallObjectsGenerator) PostConvertHook() error { + mapAddressObjectIDs := map[string]string{} + mapApplicationObjectIDs := map[string]string{} + mapServiceObjectIDs := map[string]string{} + + for _, r := range g.Resources { + if _, ok := r.Item["name"]; ok { + if r.InstanceInfo.Type == "panos_address_object" { + mapAddressObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_application_object" { + mapApplicationObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_service_object" { + mapServiceObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + } + } + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_address_group" { + if _, ok := r.Item["static_addresses"]; ok { + staticAddresses := make([]string, len(r.Item["static_addresses"].([]interface{}))) + for k, staticAddress := range r.Item["static_addresses"].([]interface{}) { + if _, ok2 := mapAddressObjectIDs[staticAddress.(string)]; ok2 { + staticAddresses[k] = mapAddressObjectIDs[staticAddress.(string)] + continue + } + staticAddresses[k] = staticAddress.(string) + } + + r.Item["static_addresses"] = staticAddresses + } + } + + if r.InstanceInfo.Type == "panos_application_group" { + if _, ok := r.Item["applications"]; ok { + applications := make([]string, len(r.Item["applications"].([]interface{}))) + for k, application := range r.Item["applications"].([]interface{}) { + if _, ok2 := mapApplicationObjectIDs[application.(string)]; ok2 { + applications[k] = mapApplicationObjectIDs[application.(string)] + continue + } + applications[k] = application.(string) + } + + r.Item["applications"] = applications + } + } + + if r.InstanceInfo.Type == "panos_service_group" { + if _, ok := r.Item["services"]; ok { + services := make([]string, len(r.Item["services"].([]interface{}))) + for k, service := range r.Item["services"].([]interface{}) { + if _, ok2 := mapServiceObjectIDs[service.(string)]; ok2 { + services[k] = mapServiceObjectIDs[service.(string)] + continue + } + services[k] = service.(string) + } + + r.Item["services"] = services + } + } + } + + return nil +} diff --git a/providers/panos/firewall_policy.go b/providers/panos/firewall_policy.go new file mode 100644 index 000000000..cecf00ea2 --- /dev/null +++ b/providers/panos/firewall_policy.go @@ -0,0 +1,114 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "encoding/base64" + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/util" +) + +type FirewallPolicyGenerator struct { + PanosService +} + +func (g *FirewallPolicyGenerator) createResourcesFromList(o getGeneric, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + var positionReference string + id := g.vsys + ":" + strconv.Itoa(util.MoveTop) + "::" + + for k, r := range l { + if k > 0 { + id = g.vsys + ":" + strconv.Itoa(util.MoveAfter) + ":" + positionReference + ":" + } + + id += base64.StdEncoding.EncodeToString([]byte(r)) + positionReference = r + + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(r), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *FirewallPolicyGenerator) createNATRuleGroupResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Policies.Nat, []string{g.vsys}}, "panos_nat_rule_group") +} + +func (g *FirewallPolicyGenerator) createPBFRuleGroupResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Policies.PolicyBasedForwarding, []string{g.vsys}}, "panos_pbf_rule_group") +} + +func (g *FirewallPolicyGenerator) createSecurityRuleGroupResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Firewall).Policies.Security, []string{g.vsys}}, "panos_security_rule_group") +} + +func (g *FirewallPolicyGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + g.Resources = append(g.Resources, g.createNATRuleGroupResources()...) + g.Resources = append(g.Resources, g.createPBFRuleGroupResources()...) + g.Resources = append(g.Resources, g.createSecurityRuleGroupResources()...) + + return nil +} + +func (g *FirewallPolicyGenerator) PostConvertHook() error { + for _, res := range g.Resources { + if res.InstanceInfo.Type == "panos_nat_rule_group" { + for _, rule := range res.Item["rule"].([]interface{}) { + if _, ok := rule.(map[string]interface{})["translated_packet"]; ok { + a := rule.(map[string]interface{})["translated_packet"].([]interface{}) + for _, b := range a { + if _, okb := b.(map[string]interface{})["source"]; !okb { + b.(map[string]interface{})["source"] = make(map[string]interface{}) + } + } + + for _, b := range a { + if _, okb := b.(map[string]interface{})["destination"]; !okb { + b.(map[string]interface{})["destination"] = make(map[string]interface{}) + } + } + } + } + } + + if res.InstanceInfo.Type == "panos_security_rule_group" { + for _, rule := range res.Item["rule"].([]interface{}) { + if _, ok := rule.(map[string]interface{})["hip_profiles"]; !ok { + rule.(map[string]interface{})["hip_profiles"] = []string{"any"} + } + } + } + } + + return nil +} diff --git a/providers/panos/helpers.go b/providers/panos/helpers.go new file mode 100644 index 000000000..6b672fa38 --- /dev/null +++ b/providers/panos/helpers.go @@ -0,0 +1,170 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "fmt" + "strings" + "unicode" + + "github.com/PaloAltoNetworks/pango" + "golang.org/x/text/secure/precis" + "golang.org/x/text/transform" + "golang.org/x/text/unicode/norm" +) + +func Initialize() (interface{}, error) { + return pango.Connect(pango.Client{ + CheckEnvironment: true, + }) +} + +func GetVsysList() ([]string, interface{}, error) { + client, err := Initialize() + if err != nil { + return []string{}, nil, err + } + + switch c := client.(type) { + case *pango.Panorama: + return []string{"shared"}, pango.Panorama{}, nil + case *pango.Firewall: + var vsysList []string + vsysList, err = c.Vsys.GetList() + return vsysList, pango.Firewall{}, err + } + + return []string{}, nil, fmt.Errorf("client type not supported") +} + +func FilterCallableResources(t interface{}, resources []string) []string { + var filteredResources []string + + switch t.(type) { + case pango.Panorama: + for _, r := range resources { + if strings.HasPrefix(r, "panorama_") { + filteredResources = append(filteredResources, r) + } + } + case pango.Firewall: + for _, r := range resources { + if strings.HasPrefix(r, "firewall_") { + filteredResources = append(filteredResources, r) + } + } + } + + return filteredResources +} + +func normalizeResourceName(s string) string { + normalize := precis.NewIdentifier( + precis.AdditionalMapping(func() transform.Transformer { + return transform.Chain(norm.NFD, transform.RemoveFunc(func(r rune) bool { //nolint + return unicode.Is(unicode.Mn, r) + })) + }), + precis.Norm(norm.NFC), + ) + + r := strings.NewReplacer(" ", "_", + "!", "_", + "\"", "_", + "#", "_", + "%", "_", + "&", "_", + "'", "_", + "(", "_", + ")", "_", + "{", "_", + "}", "_", + "*", "_", + "+", "_", + ",", "_", + "-", "_", + ".", "_", + "/", "_", + "|", "_", + "\\", "_", + ":", "_", + ";", "_", + ">", "_", + "=", "_", + "<", "_", + "?", "_", + "[", "_", + "]", "_", + "^", "_", + "`", "_", + "~", "_", + "$", "_", + "@", "_at_") + replaced := r.Replace(strings.ToLower(s)) + + result, err := normalize.String(replaced) + if err != nil { + return replaced + } + + return result +} + +type getListWithoutArg interface { + GetList() ([]string, error) +} + +type getListWithOneArg interface { + GetList(string) ([]string, error) +} + +type getListWithTwoArgs interface { + GetList(string, string) ([]string, error) +} + +type getListWithThreeArgs interface { + GetList(string, string, string) ([]string, error) +} + +type getListWithFourArgs interface { + GetList(string, string, string, string) ([]string, error) +} + +type getListWithFiveArgs interface { + GetList(string, string, string, string, string) ([]string, error) +} + +type getGeneric struct { + i interface{} + params []string +} + +func contains(s []string, e string) bool { + for _, v := range s { + if v == e { + return true + } + } + return false +} + +func mapExists(mapString map[string]string, item map[string]interface{}, element string) bool { + if _, ok := item[element]; ok { + if _, ok2 := mapString[item[element].(string)]; ok2 { + return true + } + } + return false +} diff --git a/providers/panos/panorama_device_config.go b/providers/panos/panorama_device_config.go new file mode 100644 index 000000000..6bf94ba4f --- /dev/null +++ b/providers/panos/panorama_device_config.go @@ -0,0 +1,308 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/util" +) + +type PanoramaDeviceConfigGenerator struct { + PanosService +} + +func (g *PanoramaDeviceConfigGenerator) createResourcesFromList(o getGeneric, idPrefix string, useIDForResourceName bool, terraformResourceName string) (resources []terraformutils.Resource) { + var l []string + var err error + + switch f := o.i.(type) { + case getListWithoutArg: + l, err = f.GetList() + case getListWithTwoArgs: + l, err = f.GetList(o.params[0], o.params[1]) + default: + err = fmt.Errorf("not supported") + } + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := idPrefix + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(func() string { + if useIDForResourceName { + return id + } + + return r + }()), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *PanoramaDeviceConfigGenerator) createDeviceGroupResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Panorama).Panorama.DeviceGroup, []string{}}, + "", false, "panos_panorama_device_group", + ) +} + +func (g *PanoramaDeviceConfigGenerator) createDeviceGroupParentResources() (resources []terraformutils.Resource) { + p, err := g.client.(*pango.Panorama).Panorama.DeviceGroup.GetParents() + if err != nil { + return resources + } + + for dg, parent := range p { + if parent != "" { + resources = append(resources, terraformutils.NewResource( + dg, + normalizeResourceName(dg), + "panos_device_group_parent", + "panos", + map[string]string{ + "device_group": dg, + "parent": parent, + }, + []string{}, + map[string]interface{}{}, + )) + } + } + + return resources +} + +func createAttributes(tmpl, ts, dg string) map[string]string { + attributes := make(map[string]string) + + if tmpl != "" { + attributes["template"] = tmpl + } + if ts != "" { + attributes["template_stack"] = ts + } + if dg != "" { + attributes["device_group"] = dg + } + + return attributes +} + +func createServerProfileResources(tmpl, ts, vsys, dg, terraformResourceName string, l []string) (resources []terraformutils.Resource) { + attributes := createAttributes(tmpl, ts, dg) + + for _, r := range l { + id := tmpl + ":" + ts + ":" + vsys + ":" + dg + ":" + r + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + terraformResourceName, + "panos", + attributes, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaDeviceConfigGenerator) createEmailServerProfileResources(tmpl, ts, vsys, dg string) (resources []terraformutils.Resource) { + l := make([]string, 0) + var err error + + if tmpl != "" || ts != "" { + l, err = g.client.(*pango.Panorama).Device.EmailServerProfile.GetList(tmpl, ts, vsys) + } + if dg != "" { + ans := make([]string, 0, 7) + ans = append(ans, util.DeviceGroupXpathPrefix(dg)...) + ans = append(ans, []string{"log-settings", "email"}...) + l, err = g.client.(util.XapiClient).EntryListUsing(g.client.(util.XapiClient).Get, ans) + } + + if err != nil || len(l) == 0 { + return resources + } + + return createServerProfileResources(tmpl, ts, vsys, dg, "panos_panorama_email_server_profile", l) +} + +func (g *PanoramaDeviceConfigGenerator) createHTTPServerProfileResources(tmpl, ts, vsys, dg string) (resources []terraformutils.Resource) { + l := make([]string, 0) + var err error + + if tmpl != "" || ts != "" { + l, err = g.client.(*pango.Panorama).Device.HttpServerProfile.GetList(tmpl, ts, vsys) + } + if dg != "" { + ans := make([]string, 0, 7) + ans = append(ans, util.DeviceGroupXpathPrefix(dg)...) + ans = append(ans, []string{"log-settings", "http"}...) + l, err = g.client.(util.XapiClient).EntryListUsing(g.client.(util.XapiClient).Get, ans) + } + + if err != nil || len(l) == 0 { + return resources + } + + return createServerProfileResources(tmpl, ts, vsys, dg, "panos_panorama_http_server_profile", l) +} + +func (g *PanoramaDeviceConfigGenerator) createSNMPTrapServerProfileResources(tmpl, ts, vsys, dg string) (resources []terraformutils.Resource) { + l := make([]string, 0) + var err error + + if tmpl != "" || ts != "" { + l, err = g.client.(*pango.Panorama).Device.SnmpServerProfile.GetList(tmpl, ts, vsys) + } + if dg != "" { + ans := make([]string, 0, 7) + ans = append(ans, util.DeviceGroupXpathPrefix(dg)...) + ans = append(ans, []string{"log-settings", "snmptrap"}...) + l, err = g.client.(util.XapiClient).EntryListUsing(g.client.(util.XapiClient).Get, ans) + } + + if err != nil || len(l) == 0 { + return resources + } + + return createServerProfileResources(tmpl, ts, vsys, dg, "panos_panorama_snmptrap_server_profile", l) +} + +func (g *PanoramaDeviceConfigGenerator) createSyslogServerProfileResources(tmpl, ts, vsys, dg string) (resources []terraformutils.Resource) { + l := make([]string, 0) + var err error + + if tmpl != "" || ts != "" { + l, err = g.client.(*pango.Panorama).Device.SyslogServerProfile.GetList(tmpl, ts, vsys) + } + if dg != "" { + ans := make([]string, 0, 7) + ans = append(ans, util.DeviceGroupXpathPrefix(dg)...) + ans = append(ans, []string{"log-settings", "syslog"}...) + l, err = g.client.(util.XapiClient).EntryListUsing(g.client.(util.XapiClient).Get, ans) + } + + if err != nil || len(l) == 0 { + return resources + } + + return createServerProfileResources(tmpl, ts, vsys, dg, "panos_panorama_syslog_server_profile", l) +} + +func (g *PanoramaDeviceConfigGenerator) createTemplateResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Panorama).Panorama.Template, []string{}}, + "", false, "panos_panorama_template", + ) +} + +func (g *PanoramaDeviceConfigGenerator) createTemplateStackResources() []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Panorama).Panorama.TemplateStack, []string{}}, + "", false, "panos_panorama_template_stack", + ) +} + +func (g *PanoramaDeviceConfigGenerator) createTemplateVariableResources(tmpl, ts string) []terraformutils.Resource { + return g.createResourcesFromList(getGeneric{g.client.(*pango.Panorama).Panorama.TemplateVariable, []string{tmpl, ts}}, + tmpl+":"+ts+":", true, "panos_panorama_template_variable", + ) +} + +func (g *PanoramaDeviceConfigGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + g.Resources = append(g.Resources, g.createTemplateStackResources()...) + g.Resources = append(g.Resources, g.createTemplateResources()...) + g.Resources = append(g.Resources, g.createDeviceGroupResources()...) + g.Resources = append(g.Resources, g.createDeviceGroupParentResources()...) + + ts, err := g.client.(*pango.Panorama).Panorama.TemplateStack.GetList() + if err != nil { + return err + } + + for _, v := range ts { + g.Resources = append(g.Resources, g.createTemplateVariableResources("", v)...) + + vsysList, err := g.client.(*pango.Panorama).Vsys.GetList("", v) + if err != nil { + continue + } + + vsysList = append(vsysList, "shared") + + for _, vsys := range vsysList { + g.Resources = append(g.Resources, g.createEmailServerProfileResources("", v, vsys, "")...) + g.Resources = append(g.Resources, g.createHTTPServerProfileResources("", v, vsys, "")...) + g.Resources = append(g.Resources, g.createSNMPTrapServerProfileResources("", v, vsys, "")...) + g.Resources = append(g.Resources, g.createSyslogServerProfileResources("", v, vsys, "")...) + } + } + + tmpl, err := g.client.(*pango.Panorama).Panorama.Template.GetList() + if err != nil { + return err + } + + for _, v := range tmpl { + g.Resources = append(g.Resources, g.createTemplateVariableResources(v, "")...) + + vsysList, err := g.client.(*pango.Panorama).Vsys.GetList(v, "") + if err != nil { + continue + } + if err != nil { + continue + } + + vsysList = append(vsysList, "shared") + + for _, vsys := range vsysList { + g.Resources = append(g.Resources, g.createEmailServerProfileResources(v, "", vsys, "")...) + g.Resources = append(g.Resources, g.createHTTPServerProfileResources(v, "", vsys, "")...) + g.Resources = append(g.Resources, g.createSNMPTrapServerProfileResources(v, "", vsys, "")...) + g.Resources = append(g.Resources, g.createSyslogServerProfileResources(v, "", vsys, "")...) + } + } + + dg, err := g.client.(*pango.Panorama).Panorama.DeviceGroup.GetList() + if err != nil { + return err + } + + for _, v := range dg { + g.Resources = append(g.Resources, g.createEmailServerProfileResources("", "", "", v)...) + g.Resources = append(g.Resources, g.createHTTPServerProfileResources("", "", "", v)...) + g.Resources = append(g.Resources, g.createSNMPTrapServerProfileResources("", "", "", v)...) + g.Resources = append(g.Resources, g.createSyslogServerProfileResources("", "", "", v)...) + } + + // TODO: Panorama's own profiles are not yet supported by the Terraform provider + + return nil +} diff --git a/providers/panos/panorama_networking.go b/providers/panos/panorama_networking.go new file mode 100644 index 000000000..f38aee584 --- /dev/null +++ b/providers/panos/panorama_networking.go @@ -0,0 +1,965 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/netw/interface/eth" + "github.com/PaloAltoNetworks/pango/netw/interface/subinterface/layer2" + "github.com/PaloAltoNetworks/pango/netw/interface/subinterface/layer3" + "github.com/PaloAltoNetworks/pango/util" + "github.com/PaloAltoNetworks/pango/vsys" +) + +type PanoramaNetworkingGenerator struct { + PanosService +} + +func (g *PanoramaNetworkingGenerator) createResourcesFromList( + o getGeneric, + idPrefix string, + useIDForResourceName bool, + terraformResourceName string, +) (resources []terraformutils.Resource) { + var l []string + var err error + + switch f := o.i.(type) { + case getListWithoutArg: + l, err = f.GetList() + case getListWithOneArg: + l, err = f.GetList(o.params[0]) + case getListWithTwoArgs: + l, err = f.GetList(o.params[0], o.params[1]) + case getListWithThreeArgs: + l, err = f.GetList(o.params[0], o.params[1], o.params[2]) + case getListWithFourArgs: + l, err = f.GetList(o.params[0], o.params[1], o.params[2], o.params[3]) + case getListWithFiveArgs: + l, err = f.GetList(o.params[0], o.params[1], o.params[2], o.params[3], o.params[4]) + default: + err = fmt.Errorf("not supported") + } + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := idPrefix + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(func() string { + if useIDForResourceName { + return id + } + + return r + }()), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createAggregateInterfaceResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.AggregateInterface.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, aggregateInterface := range l { + if !contains(vsys.NetworkImports.Interfaces, aggregateInterface) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, aggregateInterface) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + aggregateInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_aggregate_interface", + "panos", + []string{}, + )) + + e, err := g.client.(*pango.Panorama).Network.AggregateInterface.Get(tmpl, ts, aggregateInterface) + if err != nil { + continue + } + + if e.Mode == eth.ModeLayer2 || e.Mode == eth.ModeVirtualWire { + g.Resources = append(g.Resources, g.createLayer2SubInterfaceResources(tmpl, ts, vsys.Name, layer2.EthernetInterface, aggregateInterface, e.Mode)...) + } + + if e.Mode == eth.ModeLayer3 { + g.Resources = append(g.Resources, g.createLayer3SubInterfaceResources(tmpl, ts, vsys.Name, layer3.EthernetInterface, aggregateInterface)...) + } + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createBFDProfileResources(tmpl, ts string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BfdProfile, []string{tmpl, ts}}, + tmpl+":"+ts+":", false, "panos_panorama_bfd_profile", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPResource(tmpl, ts, virtualRouter string) terraformutils.Resource { + return terraformutils.NewSimpleResource( + tmpl+":"+ts+":"+virtualRouter, + normalizeResourceName(tmpl+":"+ts+":"+virtualRouter), + "panos_panorama_bgp", + "panos", + []string{}, + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPAggregateResources(tmpl, ts, virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.BgpAggregate.GetList(tmpl, ts, virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpAggregate := range l { + id := tmpl + ":" + ts + ":" + virtualRouter + ":" + bgpAggregate + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_bgp_aggregate", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPAggregateAdvertiseFilterResources(tmpl, ts, virtualRouter, bgpAggregate)...) + resources = append(resources, g.createBGPAggregateSuppressFilterResources(tmpl, ts, virtualRouter, bgpAggregate)...) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createBGPAggregateAdvertiseFilterResources(tmpl, ts, virtualRouter, bgpAggregate string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpAggAdvertiseFilter, []string{tmpl, ts, virtualRouter, bgpAggregate}}, + tmpl+":"+ts+":"+virtualRouter+":"+bgpAggregate+":", true, "panos_panorama_bgp_aggregate_advertise_filter", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPAggregateSuppressFilterResources(tmpl, ts, virtualRouter, bgpAggregate string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpAggSuppressFilter, []string{tmpl, ts, virtualRouter, bgpAggregate}}, + tmpl+":"+ts+":"+virtualRouter+":"+bgpAggregate+":", true, "panos_panorama_bgp_aggregate_suppress_filter", + ) +} + +// The secret argument will contain "(incorrect)", not the real value +func (g *PanoramaNetworkingGenerator) createBGPAuthProfileResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpAuthProfile, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_bgp_auth_profile", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPConditionalAdvertisementResources(tmpl, ts, virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.BgpConditionalAdv.GetList(tmpl, ts, virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpConditionalAdv := range l { + id := tmpl + ":" + ts + ":" + virtualRouter + ":" + bgpConditionalAdv + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_bgp_conditional_adv", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPConditionalAdvertisementAdvertiseFilterResources(tmpl, ts, virtualRouter, bgpConditionalAdv)...) + resources = append(resources, g.createBGPConditionalAdvertisementNonExistFilterResources(tmpl, ts, virtualRouter, bgpConditionalAdv)...) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createBGPConditionalAdvertisementAdvertiseFilterResources(tmpl, ts, virtualRouter, bgpConditionalAdv string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpConAdvAdvertiseFilter, []string{tmpl, ts, virtualRouter, bgpConditionalAdv}}, + tmpl+":"+ts+":"+virtualRouter+":"+bgpConditionalAdv+":", true, "panos_panorama_bgp_conditional_adv_advertise_filter", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPConditionalAdvertisementNonExistFilterResources(tmpl, ts, virtualRouter, bgpConditionalAdv string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpConAdvNonExistFilter, []string{tmpl, ts, virtualRouter, bgpConditionalAdv}}, + tmpl+":"+ts+":"+virtualRouter+":"+bgpConditionalAdv+":", true, "panos_panorama_bgp_conditional_adv_non_exist_filter", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPDampeningProfileResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpDampeningProfile, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_bgp_dampening_profile", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPExportRuleGroupResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpExport, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_bgp_export_rule_group", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPImportRuleGroupResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpImport, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_bgp_import_rule_group", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPPeerGroupResources(tmpl, ts, virtualRouter string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.BgpPeerGroup.GetList(tmpl, ts, virtualRouter) + if err != nil { + return []terraformutils.Resource{} + } + + for _, bgpPeerGroup := range l { + id := tmpl + ":" + ts + ":" + virtualRouter + ":" + bgpPeerGroup + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_bgp_peer_group", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPPeerResources(tmpl, ts, virtualRouter, bgpPeerGroup)...) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createBGPPeerResources(tmpl, ts, virtualRouter, bgpPeerGroup string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpPeer, []string{tmpl, ts, virtualRouter, bgpPeerGroup}}, + tmpl+":"+ts+":"+virtualRouter+":"+bgpPeerGroup+":", true, "panos_panorama_bgp_peer", + ) +} + +func (g *PanoramaNetworkingGenerator) createBGPRedistResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.BgpRedistRule, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_bgp_redist_rule", + ) +} + +func (g *PanoramaNetworkingGenerator) createEthernetInterfaceResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.EthernetInterface.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, ethernetInterface := range l { + if !contains(vsys.NetworkImports.Interfaces, ethernetInterface) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, ethernetInterface) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + ethernetInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_ethernet_interface", + "panos", + []string{}, + )) + + e, err := g.client.(*pango.Panorama).Network.EthernetInterface.Get(tmpl, ts, ethernetInterface) + if err != nil { + continue + } + + if e.Mode == eth.ModeLayer2 || e.Mode == eth.ModeVirtualWire { + g.Resources = append(g.Resources, g.createLayer2SubInterfaceResources(tmpl, ts, vsys.Name, layer2.EthernetInterface, ethernetInterface, e.Mode)...) + } + + if e.Mode == eth.ModeLayer3 { + g.Resources = append(g.Resources, g.createLayer3SubInterfaceResources(tmpl, ts, vsys.Name, layer3.EthernetInterface, ethernetInterface)...) + } + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createGRETunnelResources(tmpl, ts string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.GreTunnel, []string{tmpl, ts}}, + tmpl+":"+ts+":", false, "panos_panorama_gre_tunnel", + ) +} + +func (g *PanoramaNetworkingGenerator) createIKECryptoProfileResources(tmpl, ts string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.IkeCryptoProfile.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + idPrefix := tmpl + ":" + ts + ":" + for _, ikeCryptoProfile := range l { + id := idPrefix + ikeCryptoProfile + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + "panos_panorama_ike_crypto_profile", + "panos", + map[string]string{ + "name": ikeCryptoProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createIKEGatewayResources(tmpl, ts string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.IkeGateway.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + idPrefix := tmpl + ":" + ts + ":" + for _, ikeGateway := range l { + id := idPrefix + ikeGateway + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + "panos_panorama_ike_gateway", + "panos", + map[string]string{ + "name": ikeGateway, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createIPSECCryptoProfileResources(tmpl, ts string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.IpsecCryptoProfile.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + idPrefix := tmpl + ":" + ts + ":" + for _, ipsecCryptoProfile := range l { + id := idPrefix + ipsecCryptoProfile + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + "panos_panorama_ipsec_crypto_profile", + "panos", + map[string]string{ + "name": ipsecCryptoProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createIPSECTunnelProxyIDIPv4Resources(tmpl, ts, ipsecTunnel string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.IpsecTunnelProxyId, []string{tmpl, ts, ipsecTunnel}}, + tmpl+":"+ts+":"+ipsecTunnel+":", true, "panos_panorama_ipsec_tunnel_proxy_id_ipv4", + ) +} + +func (g *PanoramaNetworkingGenerator) createIPSECTunnelResources(tmpl, ts string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.IpsecTunnel.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + idPrefix := tmpl + "::" + for _, ipsecTunnel := range l { + id := idPrefix + ipsecTunnel + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_ipsec_tunnel", + "panos", + []string{}, + )) + + resources = append(resources, g.createIPSECTunnelProxyIDIPv4Resources(tmpl, ts, ipsecTunnel)...) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createLayer2SubInterfaceResources(tmpl, ts, vsys, interfaceType, parentInterface, parentMode string) []terraformutils.Resource { + // TO FIX: check disabled! + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.Layer2Subinterface, []string{tmpl, ts, interfaceType, parentInterface, parentMode}}, + tmpl+":"+ts+":"+interfaceType+":"+parentInterface+":"+parentMode+":"+vsys+":", true, "panos_panorama_layer2_subinterface", + ) +} + +func (g *PanoramaNetworkingGenerator) createLayer3SubInterfaceResources(tmpl, ts, vsys, interfaceType, parentInterface string) []terraformutils.Resource { + // TO FIX: check disabled! + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.Layer3Subinterface, []string{tmpl, ts, interfaceType, parentInterface}}, + tmpl+":"+ts+":"+interfaceType+":"+parentInterface+":"+vsys+":", true, "panos_panorama_layer3_subinterface", + ) +} + +func (g *PanoramaNetworkingGenerator) createLoopbackInterfaceResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.LoopbackInterface.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, loopbackInterface := range l { + if !contains(vsys.NetworkImports.Interfaces, loopbackInterface) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, loopbackInterface) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + loopbackInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_loopback_interface", + "panos", + []string{}, + )) + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createManagementProfileResources(tmpl, ts string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.ManagementProfile.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + idPrefix := tmpl + ":" + ts + ":" + for _, managementProfile := range l { + id := idPrefix + managementProfile + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + "panos_panorama_management_profile", + "panos", + map[string]string{ + "name": managementProfile, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createMonitorProfileResources(tmpl, ts string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.MonitorProfile, []string{tmpl, ts}}, + tmpl+":"+ts+":", true, "panos_panorama_monitor_profile", + ) +} + +func (g *PanoramaNetworkingGenerator) createRedistributionProfileResources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.RedistributionProfile, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_redistribution_profile_ipv4", + ) +} + +func (g *PanoramaNetworkingGenerator) createStaticRouteIpv4Resources(tmpl, ts, virtualRouter string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Network.StaticRoute, []string{tmpl, ts, virtualRouter}}, + tmpl+":"+ts+":"+virtualRouter+":", true, "panos_panorama_static_route_ipv4", + ) +} + +func (g *PanoramaNetworkingGenerator) createTunnelInterfaceResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.TunnelInterface.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, tunnelInterface := range l { + if !contains(vsys.NetworkImports.Interfaces, tunnelInterface) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, tunnelInterface) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + tunnelInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_tunnel_interface", + "panos", + []string{}, + )) + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createVirtualRouterResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.VirtualRouter.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, virtualRouter := range l { + if !contains(vsys.NetworkImports.VirtualRouters, virtualRouter) { + continue + } + + // TODO: doesn't work!!? + // rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, virtualRouter) + // if err != nil || !rv { + // continue + // } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + virtualRouter + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_virtual_router", + "panos", + []string{}, + )) + + resources = append(resources, g.createBGPResource(tmpl, ts, virtualRouter)) + resources = append(resources, g.createBGPAggregateResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPAuthProfileResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPConditionalAdvertisementResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPDampeningProfileResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPExportRuleGroupResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPImportRuleGroupResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPPeerGroupResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createBGPRedistResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createRedistributionProfileResources(tmpl, ts, virtualRouter)...) + resources = append(resources, g.createStaticRouteIpv4Resources(tmpl, ts, virtualRouter)...) + } + } + + return resources +} + +// FIX: get VLANs in Vsys = None +func (g *PanoramaNetworkingGenerator) createVlanResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.Vlan.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, vlan := range l { + if !contains(vsys.NetworkImports.Vlans, vlan) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.VlanImport, tmpl, ts, vsys.Name, vlan) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + vlan + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_vlan", + "panos", + []string{}, + )) + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createVlanInterfaceResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Network.VlanInterface.GetList(tmpl, ts) + if err != nil { + return []terraformutils.Resource{} + } + + for _, vsys := range v { + for _, vlanInterface := range l { + if !contains(vsys.NetworkImports.Interfaces, vlanInterface) { + continue + } + + rv, err := g.client.(*pango.Panorama).IsImported(util.InterfaceImport, tmpl, ts, vsys.Name, vlanInterface) + if err != nil || !rv { + continue + } + + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + vlanInterface + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_vlan_interface", + "panos", + []string{}, + )) + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) createZoneResources(tmpl, ts string, v []vsys.Entry) (resources []terraformutils.Resource) { + for _, vsys := range v { + l, err := g.client.(*pango.Panorama).Network.Zone.GetList(tmpl, ts, vsys.Name) + if err != nil { + return []terraformutils.Resource{} + } + + for _, zone := range l { + id := tmpl + ":" + ts + ":" + vsys.Name + ":" + zone + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_zone", + "panos", + []string{}, + )) + } + } + + return resources +} + +func (g *PanoramaNetworkingGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + ts, err := g.client.(*pango.Panorama).Panorama.TemplateStack.GetList() + if err != nil { + return err + } + + for _, v := range ts { + g.Resources = append(g.Resources, g.createBFDProfileResources("", v)...) + g.Resources = append(g.Resources, g.createIKECryptoProfileResources("", v)...) + g.Resources = append(g.Resources, g.createIKEGatewayResources("", v)...) + g.Resources = append(g.Resources, g.createIPSECCryptoProfileResources("", v)...) + g.Resources = append(g.Resources, g.createManagementProfileResources("", v)...) + g.Resources = append(g.Resources, g.createMonitorProfileResources("", v)...) + } + + tmpl, err := g.client.(*pango.Panorama).Panorama.Template.GetList() + if err != nil { + return err + } + + for _, v := range tmpl { + vsysAll, err := g.client.(*pango.Panorama).Vsys.GetAll(v, "") + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createAggregateInterfaceResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createBFDProfileResources(v, "")...) + g.Resources = append(g.Resources, g.createEthernetInterfaceResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createGRETunnelResources(v, "")...) + g.Resources = append(g.Resources, g.createIKECryptoProfileResources(v, "")...) + g.Resources = append(g.Resources, g.createIKEGatewayResources(v, "")...) + g.Resources = append(g.Resources, g.createIPSECCryptoProfileResources(v, "")...) + g.Resources = append(g.Resources, g.createIPSECTunnelResources(v, "")...) + g.Resources = append(g.Resources, g.createLoopbackInterfaceResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createManagementProfileResources(v, "")...) + g.Resources = append(g.Resources, g.createMonitorProfileResources(v, "")...) + g.Resources = append(g.Resources, g.createTunnelInterfaceResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createVirtualRouterResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createVlanResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createVlanInterfaceResources(v, "", vsysAll)...) + g.Resources = append(g.Resources, g.createZoneResources(v, "", vsysAll)...) + } + + return nil +} + +func (g *PanoramaNetworkingGenerator) PostConvertHook() error { + mapInterfaceNames := map[string]string{} + mapInterfaceModes := map[string]string{} + mapIKECryptoProfileNames := map[string]string{} + mapIKEGatewayNames := map[string]string{} + mapIPSECCryptoProfileNames := map[string]string{} + + for _, r := range g.Resources { + if _, ok := r.Item["name"]; ok { + if r.InstanceInfo.Type == "panos_panorama_aggregate_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + mapInterfaceModes[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".mode}" + } + + if r.InstanceInfo.Type == "panos_panorama_ethernet_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + mapInterfaceModes[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".mode}" + } + + if r.InstanceInfo.Type == "panos_panorama_layer2_subinterface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_layer3_subinterface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_loopback_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_tunnel_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_vlan_interface" { + mapInterfaceNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_ike_crypto_profile" { + mapIKECryptoProfileNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_ike_gateway" { + mapIKEGatewayNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_ipsec_crypto_profile" { + mapIPSECCryptoProfileNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + } + } + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_panorama_bgp" || + r.InstanceInfo.Type == "panos_panorama_redistribution_profile_ipv4" || + r.InstanceInfo.Type == "panos_panorama_static_route_ipv4" { + if _, ok := r.Item["virtual_router"]; ok { + if r.Item["virtual_router"].(string) != "default" { + r.Item["virtual_router"] = "${panos_panorama_virtual_router." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".name}" + } + } + } + + if r.InstanceInfo.Type == "panos_panorama_bgp_aggregate" || + r.InstanceInfo.Type == "panos_panorama_bgp_auth_profile" || + r.InstanceInfo.Type == "panos_panorama_bgp_conditional_adv" || + r.InstanceInfo.Type == "panos_panorama_bgp_dampening_profile" || + r.InstanceInfo.Type == "panos_panorama_bgp_export_rule_group" || + r.InstanceInfo.Type == "panos_panorama_bgp_import_rule_group" || + r.InstanceInfo.Type == "panos_panorama_bgp_peer_group" || + r.InstanceInfo.Type == "panos_panorama_bgp_redist_rule" { + if _, ok := r.Item["virtual_router"]; ok { + if r.Item["virtual_router"].(string) != "default" { + r.Item["virtual_router"] = "${panos_panorama_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + } + } + + if r.InstanceInfo.Type == "panos_panorama_bgp_aggregate_advertise_filter" || + r.InstanceInfo.Type == "panos_panorama_bgp_aggregate_suppress_filter" { + if _, ok := r.Item["virtual_router"]; ok { + if r.Item["virtual_router"].(string) != "default" { + r.Item["virtual_router"] = "${panos_panorama_bgp_aggregate." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + } + if _, ok := r.Item["bgp_aggregate"]; ok { + r.Item["bgp_aggregate"] = "${panos_panorama_bgp_aggregate." + normalizeResourceName(r.Item["bgp_aggregate"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_panorama_bgp_peer" { + if _, ok := r.Item["virtual_router"]; ok { + if r.Item["virtual_router"].(string) != "default" { + r.Item["virtual_router"] = "${panos_panorama_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + r.Item["peer_as"] = "${panos_panorama_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".as_number}" + } + } + if _, ok := r.Item["panos_bgp_peer_group"]; ok { + r.Item["bgp_peer_group"] = "${panos_panorama_bgp_peer_group." + normalizeResourceName(r.Item["panos_bgp_peer_group"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_panorama_bgp_conditional_adv_advertise_filter" || + r.InstanceInfo.Type == "panos_panorama_bgp_conditional_adv_non_exist_filter" { + if _, ok := r.Item["virtual_router"]; ok { + if r.Item["virtual_router"].(string) != "default" { + r.Item["virtual_router"] = "${panos_panorama_bgp." + normalizeResourceName(r.Item["virtual_router"].(string)) + ".virtual_router}" + } + } + if _, ok := r.Item["panos_bgp_conditional_adv"]; ok { + r.Item["bgp_conditional_adv"] = "${panos_panorama_bgp_conditional_adv." + normalizeResourceName(r.Item["panos_bgp_conditional_adv"].(string)) + ".name}" + } + } + + if r.InstanceInfo.Type == "panos_panorama_gre_tunnel" { + if mapExists(mapInterfaceNames, r.Item, "interface") { + r.Item["interface"] = mapInterfaceNames[r.Item["interface"].(string)] + } + if mapExists(mapInterfaceNames, r.Item, "tunnel_interface") { + r.Item["tunnel_interface"] = mapInterfaceNames[r.Item["tunnel_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_ike_gateway" { + if mapExists(mapIKECryptoProfileNames, r.Item, "ikev1_crypto_profile") { + r.Item["ikev1_crypto_profile"] = mapIKECryptoProfileNames[r.Item["ikev1_crypto_profile"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_ipsec_tunnel" { + if mapExists(mapInterfaceNames, r.Item, "tunnel_interface") { + r.Item["tunnel_interface"] = mapInterfaceNames[r.Item["tunnel_interface"].(string)] + } + if mapExists(mapIKEGatewayNames, r.Item, "ak_ike_gateway") { + r.Item["ak_ike_gateway"] = mapIKEGatewayNames[r.Item["ak_ike_gateway"].(string)] + } + if mapExists(mapIPSECCryptoProfileNames, r.Item, "ak_ipsec_crypto_profile") { + r.Item["ak_ipsec_crypto_profile"] = mapIPSECCryptoProfileNames[r.Item["ak_ipsec_crypto_profile"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_ipsec_tunnel_proxy_id_ipv4" { + if mapExists(mapInterfaceNames, r.Item, "tunnel_interface") { + r.Item["tunnel_interface"] = mapInterfaceNames[r.Item["tunnel_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_layer2_subinterface" { + if mapExists(mapInterfaceModes, r.Item, "parent_interface") { + r.Item["parent_mode"] = mapInterfaceModes[r.Item["parent_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_layer2_subinterface" || + r.InstanceInfo.Type == "panos_panorama_layer3_subinterface" { + if mapExists(mapInterfaceNames, r.Item, "parent_interface") { + r.Item["parent_interface"] = mapInterfaceNames[r.Item["parent_interface"].(string)] + } + } + + if r.InstanceInfo.Type == "panos_panorama_virtual_router" { + if r.Item["ospfv3_ext_dist"].(string) == "0" { + r.Item["ospfv3_ext_dist"] = "110" + } + + if r.Item["ebgp_dist"].(string) == "0" { + r.Item["ebgp_dist"] = "20" + } + + if r.Item["rip_dist"].(string) == "0" { + r.Item["rip_dist"] = "120" + } + + if r.Item["ibgp_dist"].(string) == "0" { + r.Item["ibgp_dist"] = "200" + } + + if r.Item["static_dist"].(string) == "0" { + r.Item["static_dist"] = "10" + } + + if r.Item["ospf_int_dist"].(string) == "0" { + r.Item["ospf_int_dist"] = "30" + } + + if r.Item["static_ipv6_dist"].(string) == "0" { + r.Item["static_ipv6_dist"] = "10" + } + + if r.Item["ospf_ext_dist"].(string) == "0" { + r.Item["ospf_ext_dist"] = "110" + } + + if r.Item["ospfv3_int_dist"].(string) == "0" { + r.Item["ospfv3_int_dist"] = "30" + } + } + + if r.InstanceInfo.Type == "panos_panorama_virtual_router" || + r.InstanceInfo.Type == "panos_panorama_zone" { + if _, ok := r.Item["interfaces"]; ok { + interfaces := make([]string, len(r.Item["interfaces"].([]interface{}))) + for k, eth := range r.Item["interfaces"].([]interface{}) { + if name, ok2 := mapInterfaceNames[eth.(string)]; ok2 { + interfaces[k] = name + continue + } + interfaces[k] = eth.(string) + } + + r.Item["interfaces"] = interfaces + } + } + + if r.InstanceInfo.Type == "panos_panorama_vlan" { + if mapExists(mapInterfaceNames, r.Item, "vlan_interface") { + r.Item["vlan_interface"] = mapInterfaceNames[r.Item["vlan_interface"].(string)] + } + } + } + + return nil +} diff --git a/providers/panos/panorama_objects.go b/providers/panos/panorama_objects.go new file mode 100644 index 000000000..7993435e1 --- /dev/null +++ b/providers/panos/panorama_objects.go @@ -0,0 +1,302 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" +) + +type PanoramaObjectsGenerator struct { + PanosService +} + +func (g *PanoramaObjectsGenerator) createResourcesFromList(o getGeneric, dg string, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithOneArg).GetList(o.params[0]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := dg + ":" + r + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(id), + terraformResourceName, + "panos", + map[string]string{ + "device_group": dg, + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaObjectsGenerator) createAddressGroupResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.AddressGroup, []string{dg}}, + dg, "panos_panorama_address_group", + ) +} + +func (g *PanoramaObjectsGenerator) createAdministrativeTagResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.Tags, []string{dg}}, + dg, "panos_panorama_administrative_tag", + ) +} + +func (g *PanoramaObjectsGenerator) createApplicationGroupResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.AppGroup, []string{dg}}, + dg, "panos_panorama_application_group", + ) +} + +func (g *PanoramaObjectsGenerator) createApplicationObjectResources(dg string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Objects.Application.GetList(dg) + if err != nil { + return []terraformutils.Resource{} + } + + for _, r := range l { + id := dg + ":" + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_application_object", + "panos", + []string{}, + )) + + // TODO + // resources = append(resources, g.createApplicationSignatureResources(dg, r)...) + } + + return resources +} + +func (g *PanoramaObjectsGenerator) createEDLResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.Edl, []string{dg}}, + dg, "panos_panorama_edl", + ) +} + +func (g *PanoramaObjectsGenerator) createLogForwardingResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.LogForwardingProfile, []string{dg}}, + dg, "panos_panorama_log_forwarding_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createServiceGroupResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.ServiceGroup, []string{dg}}, + dg, "panos_panorama_service_group", + ) +} + +func (g *PanoramaObjectsGenerator) createServiceObjectResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.Services, []string{dg}}, + dg, "panos_panorama_service_object", + ) +} + +func (g *PanoramaObjectsGenerator) createAddressObjectResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.Address, []string{dg}}, + dg, "panos_address_object", + ) +} + +func (g *PanoramaObjectsGenerator) createAntiSpywareSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.AntiSpywareProfile, []string{dg}}, + dg, "panos_anti_spyware_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createAntivirusSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.AntivirusProfile, []string{dg}}, + dg, "panos_antivirus_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createCustomDataPatternObjectResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.DataPattern, []string{dg}}, + dg, "panos_custom_data_pattern_object", + ) +} + +func (g *PanoramaObjectsGenerator) createDataFilteringSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.DataFilteringProfile, []string{dg}}, + dg, "panos_data_filtering_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createDOSProtectionProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.DosProtectionProfile, []string{dg}}, + dg, "panos_dos_protection_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createDynamicUserGroupResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.DynamicUserGroup, []string{dg}}, + dg, "panos_dynamic_user_group", + ) +} + +func (g *PanoramaObjectsGenerator) createFileBlockingSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.FileBlockingProfile, []string{dg}}, + dg, "panos_file_blocking_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createURLFilteringSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.UrlFilteringProfile, []string{dg}}, + dg, "panos_url_filtering_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createVulnerabilitySecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.VulnerabilityProfile, []string{dg}}, + dg, "panos_vulnerability_security_profile", + ) +} + +func (g *PanoramaObjectsGenerator) createWildfireAnalysisSecurityProfileResources(dg string) []terraformutils.Resource { + return g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Objects.WildfireAnalysisProfile, []string{dg}}, + dg, "panos_wildfire_analysis_security_profile", + ) +} +func (g *PanoramaObjectsGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + dg, err := g.client.(*pango.Panorama).Panorama.DeviceGroup.GetList() + if err != nil { + return err + } + + for _, v := range dg { + g.Resources = append(g.Resources, g.createAddressGroupResources(v)...) + g.Resources = append(g.Resources, g.createAdministrativeTagResources(v)...) + g.Resources = append(g.Resources, g.createApplicationGroupResources(v)...) + g.Resources = append(g.Resources, g.createApplicationObjectResources(v)...) + g.Resources = append(g.Resources, g.createEDLResources(v)...) + g.Resources = append(g.Resources, g.createLogForwardingResources(v)...) + g.Resources = append(g.Resources, g.createServiceGroupResources(v)...) + g.Resources = append(g.Resources, g.createServiceObjectResources(v)...) + g.Resources = append(g.Resources, g.createAddressObjectResources(v)...) + g.Resources = append(g.Resources, g.createAntiSpywareSecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createAntivirusSecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createCustomDataPatternObjectResources(v)...) + g.Resources = append(g.Resources, g.createDataFilteringSecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createDOSProtectionProfileResources(v)...) + g.Resources = append(g.Resources, g.createDynamicUserGroupResources(v)...) + g.Resources = append(g.Resources, g.createFileBlockingSecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createURLFilteringSecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createVulnerabilitySecurityProfileResources(v)...) + g.Resources = append(g.Resources, g.createWildfireAnalysisSecurityProfileResources(v)...) + } + + return nil +} + +func (g *PanoramaObjectsGenerator) PostConvertHook() error { + mapAddressObjectIDs := map[string]string{} + mapApplicationObjectIDs := map[string]string{} + mapServiceObjectIDs := map[string]string{} + + for _, r := range g.Resources { + if _, ok := r.Item["name"]; ok { + if r.InstanceInfo.Type == "panos_address_object" { + mapAddressObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_application_object" { + mapApplicationObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + + if r.InstanceInfo.Type == "panos_panorama_service_object" { + mapServiceObjectIDs[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + } + } + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_panorama_address_group" { + if _, ok := r.Item["static_addresses"]; ok { + staticAddresses := make([]string, len(r.Item["static_addresses"].([]interface{}))) + for k, staticAddress := range r.Item["static_addresses"].([]interface{}) { + if _, ok2 := mapAddressObjectIDs[staticAddress.(string)]; ok2 { + staticAddresses[k] = mapAddressObjectIDs[staticAddress.(string)] + continue + } + staticAddresses[k] = staticAddress.(string) + } + + r.Item["static_addresses"] = staticAddresses + } + } + + if r.InstanceInfo.Type == "panos_panorama_application_group" { + if _, ok := r.Item["applications"]; ok { + applications := make([]string, len(r.Item["applications"].([]interface{}))) + for k, application := range r.Item["applications"].([]interface{}) { + if _, ok2 := mapApplicationObjectIDs[application.(string)]; ok2 { + applications[k] = mapApplicationObjectIDs[application.(string)] + continue + } + applications[k] = application.(string) + } + + r.Item["applications"] = applications + } + } + + if r.InstanceInfo.Type == "panos_panorama_service_group" { + if _, ok := r.Item["services"]; ok { + services := make([]string, len(r.Item["services"].([]interface{}))) + for k, service := range r.Item["services"].([]interface{}) { + if _, ok2 := mapServiceObjectIDs[service.(string)]; ok2 { + services[k] = mapServiceObjectIDs[service.(string)] + continue + } + services[k] = service.(string) + } + + r.Item["services"] = services + } + } + } + + return nil +} diff --git a/providers/panos/panorama_plugins.go b/providers/panos/panorama_plugins.go new file mode 100644 index 000000000..946ec082c --- /dev/null +++ b/providers/panos/panorama_plugins.go @@ -0,0 +1,115 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" +) + +type PanoramaPluginsGenerator struct { + PanosService +} + +func (g *PanoramaPluginsGenerator) createGCPAccountResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Panorama.GcpAccount.GetList() + if err != nil || len(l) == 0 { + return resources + } + + for _, r := range l { + resources = append(resources, terraformutils.NewSimpleResource( + r, + normalizeResourceName(r), + "panos_panorama_gcp_account", + "panos", + []string{}, + )) + } + + return resources +} + +func (g *PanoramaPluginsGenerator) createGKEClusterResources(group string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Panorama.GkeCluster.GetList(group) + if err != nil || len(l) == 0 { + return resources + } + + for _, r := range l { + id := group + ":" + r + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(id), + "panos_panorama_gke_cluster", + "panos", + []string{}, + )) + } + + return resources +} + +func (g *PanoramaPluginsGenerator) createGKEClusterGroupResources() (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Panorama.GkeClusterGroup.GetList() + if err != nil || len(l) == 0 { + return resources + } + + for _, r := range l { + resources = append(resources, terraformutils.NewSimpleResource( + r, + normalizeResourceName(r), + "panos_panorama_gke_cluster_group", + "panos", + []string{}, + )) + + resources = append(resources, g.createGKEClusterResources(r)...) + } + + return resources +} + +func (g *PanoramaPluginsGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + g.Resources = append(g.Resources, g.createGCPAccountResources()...) + g.Resources = append(g.Resources, g.createGKEClusterGroupResources()...) + + return nil +} + +func (g *PanoramaPluginsGenerator) PostConvertHook() error { + mapGKEClusterGroupNames := map[string]string{} + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_panorama_gke_cluster_group" { + mapGKEClusterGroupNames[r.Item["name"].(string)] = "${" + r.InstanceInfo.Type + "." + r.ResourceName + ".name}" + } + } + + for _, r := range g.Resources { + if r.InstanceInfo.Type == "panos_panorama_gke_cluster" { + if mapExists(mapGKEClusterGroupNames, r.Item, "gke_cluster_group") { + r.Item["gke_cluster_group"] = mapGKEClusterGroupNames[r.Item["gke_cluster_group"].(string)] + } + } + } + + return nil +} diff --git a/providers/panos/panorama_policy.go b/providers/panos/panorama_policy.go new file mode 100644 index 000000000..9af122be6 --- /dev/null +++ b/providers/panos/panorama_policy.go @@ -0,0 +1,192 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "encoding/base64" + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/util" +) + +type PanoramaPolicyGenerator struct { + PanosService +} + +func (g *PanoramaPolicyGenerator) createResourcesFromList(o getGeneric, terraformResourceName string) (resources []terraformutils.Resource) { + l, err := o.i.(getListWithTwoArgs).GetList(o.params[0], o.params[1]) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + var positionReference string + id := o.params[0] + ":" + o.params[1] + ":" + strconv.Itoa(util.MoveTop) + "::" + + for k, r := range l { + if k > 0 { + id = o.params[0] + ":" + o.params[1] + ":" + strconv.Itoa(util.MoveAfter) + ":" + positionReference + ":" + } + + id += base64.StdEncoding.EncodeToString([]byte(r)) + positionReference = r + + resources = append(resources, terraformutils.NewSimpleResource( + id, + normalizeResourceName(o.params[0]+":"+o.params[1]+":"+r), + terraformResourceName, + "panos", + []string{}, + )) + } + + return resources +} + +func (g *PanoramaPolicyGenerator) createNATRuleGroupResources(dg string) (resources []terraformutils.Resource) { + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.Nat, []string{dg, util.PreRulebase}}, + "panos_panorama_nat_rule_group")..., + ) + + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.Nat, []string{dg, util.Rulebase}}, + "panos_panorama_nat_rule_group")..., + ) + + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.Nat, []string{dg, util.PostRulebase}}, + "panos_panorama_nat_rule_group")..., + ) + + return resources +} + +func (g *PanoramaPolicyGenerator) createPBFRuleGroupResources(dg string) (resources []terraformutils.Resource) { + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.PolicyBasedForwarding, []string{dg, util.PreRulebase}}, + "panos_panorama_pbf_rule_group")..., + ) + + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.PolicyBasedForwarding, []string{dg, util.Rulebase}}, + "panos_panorama_pbf_rule_group")..., + ) + + resources = append(resources, g.createResourcesFromList( + getGeneric{g.client.(*pango.Panorama).Policies.PolicyBasedForwarding, []string{dg, util.PostRulebase}}, + "panos_panorama_pbf_rule_group")..., + ) + + return resources +} + +func (g *PanoramaPolicyGenerator) createSecurityRuleGroupRulebaseResources(dg, rulebase string) (resources []terraformutils.Resource) { + l, err := g.client.(*pango.Panorama).Policies.Security.GetList(dg, rulebase) + if err != nil || len(l) == 0 { + return []terraformutils.Resource{} + } + + var positionReference string + id := dg + ":" + rulebase + ":" + strconv.Itoa(util.MoveTop) + "::" + + for k, r := range l { + if k > 0 { + id = dg + ":" + rulebase + ":" + strconv.Itoa(util.MoveAfter) + ":" + positionReference + ":" + } + + id += base64.StdEncoding.EncodeToString([]byte(r)) + positionReference = r + + resources = append(resources, terraformutils.NewResource( + id, + normalizeResourceName(dg+":"+rulebase+":"+r), + "panos_panorama_security_rule_group", + "panos", + map[string]string{ + "device_group": dg, + "rulebase": rulebase, + "rule.#": "1", // Add just enough attributes to make the refresh work... + "rule.0.name": r, // Add just enough attributes to make the refresh work... + "rule.0.target.#": "0", // Add just enough attributes to make the refresh work... + }, + []string{}, + map[string]interface{}{}, + )) + } + + return resources +} + +func (g *PanoramaPolicyGenerator) createSecurityRuleGroupResources(dg string) (resources []terraformutils.Resource) { + resources = append(resources, g.createSecurityRuleGroupRulebaseResources(dg, util.PreRulebase)...) + resources = append(resources, g.createSecurityRuleGroupRulebaseResources(dg, util.Rulebase)...) + resources = append(resources, g.createSecurityRuleGroupRulebaseResources(dg, util.PostRulebase)...) + + return resources +} + +func (g *PanoramaPolicyGenerator) InitResources() error { + if err := g.Initialize(); err != nil { + return err + } + + dg, err := g.client.(*pango.Panorama).Panorama.DeviceGroup.GetList() + if err != nil { + return err + } + + for _, v := range dg { + g.Resources = append(g.Resources, g.createNATRuleGroupResources(v)...) + g.Resources = append(g.Resources, g.createPBFRuleGroupResources(v)...) + g.Resources = append(g.Resources, g.createSecurityRuleGroupResources(v)...) + } + + return nil +} + +func (g *PanoramaPolicyGenerator) PostConvertHook() error { + for _, res := range g.Resources { + if res.InstanceInfo.Type == "panos_panorama_nat_rule_group" { + for _, rule := range res.Item["rule"].([]interface{}) { + if _, ok := rule.(map[string]interface{})["translated_packet"]; ok { + a := rule.(map[string]interface{})["translated_packet"].([]interface{}) + for _, b := range a { + if _, okb := b.(map[string]interface{})["source"]; !okb { + b.(map[string]interface{})["source"] = make(map[string]interface{}) + } + } + + for _, b := range a { + if _, okb := b.(map[string]interface{})["destination"]; !okb { + b.(map[string]interface{})["destination"] = make(map[string]interface{}) + } + } + } + } + } + + if res.InstanceInfo.Type == "panos_panorama_security_rule_group" { + for _, rule := range res.Item["rule"].([]interface{}) { + if _, ok := rule.(map[string]interface{})["hip_profiles"]; !ok { + rule.(map[string]interface{})["hip_profiles"] = []string{"any"} + } + } + } + } + + return nil +} diff --git a/providers/panos/panos_provider.go b/providers/panos/panos_provider.go new file mode 100644 index 000000000..3aa0b7ef6 --- /dev/null +++ b/providers/panos/panos_provider.go @@ -0,0 +1,86 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "errors" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/zclconf/go-cty/cty" +) + +type PanosProvider struct { //nolint + terraformutils.Provider + vsys string +} + +func (p *PanosProvider) Init(args []string) error { + p.vsys = args[0] + + return nil +} + +func (p *PanosProvider) GetName() string { + return "panos" +} + +func (p *PanosProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{} +} + +func (p *PanosProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{}) +} + +func (p *PanosProvider) GetBasicConfig() cty.Value { + return p.GetConfig() +} + +func (p *PanosProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New(p.GetName() + ": " + serviceName + " not supported service") + } + + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "vsys": p.vsys, + }) + + return nil +} + +func (p *PanosProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + + return map[string]terraformutils.ServiceGenerator{ + "firewall_device_config": &FirewallDeviceConfigGenerator{}, + "firewall_networking": &FirewallNetworkingGenerator{}, + "firewall_objects": &FirewallObjectsGenerator{}, + "firewall_policy": &FirewallPolicyGenerator{}, + "panorama_device_config": &PanoramaDeviceConfigGenerator{}, + "panorama_networking": &PanoramaNetworkingGenerator{}, + "panorama_objects": &PanoramaObjectsGenerator{}, + "panorama_plugins": &PanoramaPluginsGenerator{}, + "panorama_policy": &PanoramaPolicyGenerator{}, + } +} + +func (PanosProvider) GetResourceConnections() map[string]map[string][]string { + + return map[string]map[string][]string{} +} diff --git a/providers/panos/panos_service.go b/providers/panos/panos_service.go new file mode 100644 index 000000000..1496e8a74 --- /dev/null +++ b/providers/panos/panos_service.go @@ -0,0 +1,44 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package panos + +import ( + "errors" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type PanosService struct { //nolint + terraformutils.Service + client interface{} + vsys string +} + +func (p *PanosService) Initialize() error { + if _, ok := p.Args["vsys"].(string); ok { + p.vsys = p.Args["vsys"].(string) + } else { + return errors.New(p.GetName() + ": " + "vsys name not parsable") + } + + c, err := Initialize() + if err != nil { + return err + } + + p.client = c + + return nil +} diff --git a/providers/rabbitmq/rabbitmq_provider.go b/providers/rabbitmq/rabbitmq_provider.go index 264654fab..39e7ed470 100644 --- a/providers/rabbitmq/rabbitmq_provider.go +++ b/providers/rabbitmq/rabbitmq_provider.go @@ -81,6 +81,7 @@ func (p *RBTProvider) GetSupportedService() map[string]terraformutils.ServiceGen "queues": &QueueGenerator{}, "users": &UserGenerator{}, "vhosts": &VhostGenerator{}, + "shovels": &ShovelGenerator{}, } } @@ -94,6 +95,9 @@ func (RBTProvider) GetResourceConnections() map[string]map[string][]string { "exchanges": { "vhosts": []string{"vhost", "self_link"}, }, + "shovels": { + "vhosts": []string{"vhost", "self_link"}, + }, "permissions": { "users": []string{"user", "self_link"}, "vhosts": []string{"vhost", "self_link"}, diff --git a/providers/rabbitmq/shovel.go b/providers/rabbitmq/shovel.go new file mode 100644 index 000000000..5c635509f --- /dev/null +++ b/providers/rabbitmq/shovel.go @@ -0,0 +1,72 @@ +// Copyright 2018 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rabbitmq + +import ( + "encoding/json" + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type ShovelGenerator struct { + RBTService +} + +type Shovel struct { + Name string `json:"name"` + Vhost string `json:"vhost"` +} + +type Shovels []Shovel + +var ShovelAllowEmptyValues = []string{} +var ShovelAdditionalFields = map[string]interface{}{} + +func (g ShovelGenerator) createResources(shovels Shovels) []terraformutils.Resource { + var resources []terraformutils.Resource + for _, shovel := range shovels { + if len(shovel.Name) == 0 { + continue + } + resources = append(resources, terraformutils.NewResource( + fmt.Sprintf("%s@%s", shovel.Name, shovel.Vhost), + fmt.Sprintf("shovel_%s_%s", normalizeResourceName(shovel.Vhost), normalizeResourceName(shovel.Name)), + "rabbitmq_shovel", + "rabbitmq", + map[string]string{ + "name": shovel.Name, + "vhost": shovel.Vhost, + }, + ShovelAllowEmptyValues, + ShovelAdditionalFields, + )) + } + return resources +} + +func (g *ShovelGenerator) InitResources() error { + body, err := g.generateRequest("/api/shovels?columns=name,vhost") + if err != nil { + return err + } + var shovels Shovels + err = json.Unmarshal(body, &shovels) + if err != nil { + return err + } + g.Resources = g.createResources(shovels) + return nil +} diff --git a/providers/tencentcloud/as.go b/providers/tencentcloud/as.go new file mode 100755 index 000000000..21999612d --- /dev/null +++ b/providers/tencentcloud/as.go @@ -0,0 +1,141 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + as "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/as/v20180419" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type AsGenerator struct { + TencentCloudService +} + +func (g *AsGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := as.NewClient(&credential, region, profile) + if err != nil { + return err + } + + if err := g.loadScalingGroups(client); err != nil { + return err + } + if err := g.loadScalingConfigs(client); err != nil { + return err + } + + return nil +} + +func (g *AsGenerator) loadScalingGroups(client *as.Client) error { + request := as.NewDescribeAutoScalingGroupsRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*as.AutoScalingGroup, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeAutoScalingGroups(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.AutoScalingGroupSet...) + if len(response.Response.AutoScalingGroupSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.AutoScalingGroupId, + *instance.AutoScalingGroupName+"_"+*instance.AutoScalingGroupId, + "tencentcloud_as_scaling_group", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} + +func (g *AsGenerator) loadScalingConfigs(client *as.Client) error { + request := as.NewDescribeLaunchConfigurationsRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*as.LaunchConfiguration, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeLaunchConfigurations(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.LaunchConfigurationSet...) + if len(response.Response.LaunchConfigurationSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.LaunchConfigurationId, + *instance.LaunchConfigurationName+"_"+*instance.LaunchConfigurationId, + "tencentcloud_as_scaling_config", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} + +func (g *AsGenerator) PostConvertHook() error { + for i, resource := range g.Resources { + if resource.InstanceInfo.Type != "tencentcloud_as_scaling_group" { + continue + } + if configID, exist := resource.InstanceState.Attributes["configuration_id"]; exist { + for _, r := range g.Resources { + if r.InstanceInfo.Type != "tencentcloud_as_scaling_config" { + continue + } + if configID == r.InstanceState.Attributes["id"] { + g.Resources[i].Item["configuration_id"] = "${tencentcloud_as_scaling_config." + r.ResourceName + ".id}" + } + } + } + } + + return nil +} diff --git a/providers/tencentcloud/cbs.go b/providers/tencentcloud/cbs.go new file mode 100755 index 000000000..6694c79d4 --- /dev/null +++ b/providers/tencentcloud/cbs.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + cbs "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cbs/v20170312" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type CbsGenerator struct { + TencentCloudService +} + +func (g *CbsGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cbs.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := cbs.NewDescribeDisksRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*cbs.Disk, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeDisks(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.DiskSet...) + if len(response.Response.DiskSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.DiskId, + *instance.DiskId, + "tencentcloud_cbs_storage", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/cdn.go b/providers/tencentcloud/cdn.go new file mode 100755 index 000000000..7ba70093f --- /dev/null +++ b/providers/tencentcloud/cdn.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + cdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type CdnGenerator struct { + TencentCloudService +} + +func (g *CdnGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cdn.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := cdn.NewDescribeDomainsConfigRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*cdn.DetailDomain, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeDomainsConfig(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.Domains...) + if len(response.Response.Domains) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.Domain, + *instance.Domain, + "tencentcloud_cdn_domain", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/cfs.go b/providers/tencentcloud/cfs.go new file mode 100755 index 000000000..835366509 --- /dev/null +++ b/providers/tencentcloud/cfs.go @@ -0,0 +1,57 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + cfs "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cfs/v20190719" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type CfsGenerator struct { + TencentCloudService +} + +func (g *CfsGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cfs.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := cfs.NewDescribeCfsFileSystemsRequest() + response, err := client.DescribeCfsFileSystems(request) + if err != nil { + return err + } + + for _, instance := range response.Response.FileSystems { + resource := terraformutils.NewResource( + *instance.FileSystemId, + *instance.FsName+"_"+*instance.FileSystemId, + "tencentcloud_cfs_file_system", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/clb.go b/providers/tencentcloud/clb.go new file mode 100755 index 000000000..fb19bc4ea --- /dev/null +++ b/providers/tencentcloud/clb.go @@ -0,0 +1,71 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + clb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type ClbGenerator struct { + TencentCloudService +} + +func (g *ClbGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := clb.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := clb.NewDescribeLoadBalancersRequest() + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*clb.LoadBalancer, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeLoadBalancers(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.LoadBalancerSet...) + if len(response.Response.LoadBalancerSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.LoadBalancerId, + *instance.LoadBalancerName+"_"+*instance.LoadBalancerId, + "tencentcloud_clb_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/cos.go b/providers/tencentcloud/cos.go new file mode 100755 index 000000000..aa5ac038a --- /dev/null +++ b/providers/tencentcloud/cos.go @@ -0,0 +1,66 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "context" + "fmt" + "net/http" + "net/url" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentyun/cos-go-sdk-v5" +) + +type CosGenerator struct { + TencentCloudService +} + +func (g *CosGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + requestURL := fmt.Sprintf("https://cos.%s.myqcloud.com", region) + u, _ := url.Parse(requestURL) + uri := &cos.BaseURL{ServiceURL: u} + client := cos.NewClient(uri, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: credential.SecretId, + SecretKey: credential.SecretKey, + SessionToken: credential.Token, + }, + }) + + result, _, err := client.Service.Get(context.Background()) + if err != nil { + return err + } + + for _, bucket := range result.Buckets { + resource := terraformutils.NewResource( + bucket.Name, + bucket.Name, + "tencentcloud_cos_bucket", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/cvm.go b/providers/tencentcloud/cvm.go new file mode 100755 index 000000000..4b5810500 --- /dev/null +++ b/providers/tencentcloud/cvm.go @@ -0,0 +1,76 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" +) + +type CvmGenerator struct { + TencentCloudService +} + +func (g *CvmGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cvm.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := cvm.NewDescribeInstancesRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*cvm.Instance, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.InstanceSet...) + if len(response.Response.InstanceSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_instance", + "tencentcloud", + map[string]string{ + "disable_monitor_service": "false", + "disable_security_service": "false", + "force_delete": "false", + }, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/elasticsearch.go b/providers/tencentcloud/elasticsearch.go new file mode 100755 index 000000000..34ba27ee9 --- /dev/null +++ b/providers/tencentcloud/elasticsearch.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + es "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/es/v20180416" +) + +type EsGenerator struct { + TencentCloudService +} + +func (g *EsGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := es.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := es.NewDescribeInstancesRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*es.InstanceInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.InstanceList...) + if len(response.Response.InstanceList) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_elasticsearch_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/gaap.go b/providers/tencentcloud/gaap.go new file mode 100755 index 000000000..017a24d76 --- /dev/null +++ b/providers/tencentcloud/gaap.go @@ -0,0 +1,123 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + gaap "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap/v20180529" +) + +type GaapGenerator struct { + TencentCloudService +} + +func (g *GaapGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := gaap.NewClient(&credential, region, profile) + if err != nil { + return err + } + + if err := g.loadProxy(client); err != nil { + return err + } + if err := g.loadRealServer(client); err != nil { + return err + } + + return nil +} + +func (g *GaapGenerator) loadProxy(client *gaap.Client) error { + request := gaap.NewDescribeProxiesRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*gaap.ProxyInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeProxies(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.ProxySet...) + if len(response.Response.ProxySet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.ProxyId, + *instance.ProxyName+"_"+*instance.ProxyId, + "tencentcloud_gaap_proxy", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} + +func (g *GaapGenerator) loadRealServer(client *gaap.Client) error { + request := gaap.NewDescribeRealServersRequest() + var projectID int64 = -1 + request.ProjectId = &projectID + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*gaap.BindRealServerInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeRealServers(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.RealServerSet...) + if len(response.Response.RealServerSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.RealServerId, + *instance.RealServerName+"_"+*instance.RealServerId, + "tencentcloud_gaap_realserver", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/key_pair.go b/providers/tencentcloud/key_pair.go new file mode 100755 index 000000000..a24455447 --- /dev/null +++ b/providers/tencentcloud/key_pair.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" +) + +type KeyPairGenerator struct { + TencentCloudService +} + +func (g *KeyPairGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cvm.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := cvm.NewDescribeKeyPairsRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*cvm.KeyPair, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeKeyPairs(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.KeyPairSet...) + if len(response.Response.KeyPairSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.KeyId, + *instance.KeyName+"_"+*instance.KeyId, + "tencentcloud_key_pair", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/mongodb.go b/providers/tencentcloud/mongodb.go new file mode 100755 index 000000000..cdabfd6c9 --- /dev/null +++ b/providers/tencentcloud/mongodb.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + mongodb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/mongodb/v20180408" +) + +type MongodbGenerator struct { + TencentCloudService +} + +func (g *MongodbGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := mongodb.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := mongodb.NewDescribeDBInstancesRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*mongodb.MongoDBInstanceDetail, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeDBInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.InstanceDetails...) + if len(response.Response.InstanceDetails) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_mongodb_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/mysql.go b/providers/tencentcloud/mysql.go new file mode 100755 index 000000000..0389998c9 --- /dev/null +++ b/providers/tencentcloud/mysql.go @@ -0,0 +1,149 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + cdb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb/v20170320" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" +) + +type MysqlGenerator struct { + TencentCloudService +} + +func (g *MysqlGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := cdb.NewClient(&credential, region, profile) + if err != nil { + return err + } + + if err := g.loadMysqlMaster(client); err != nil { + return err + } + if err := g.loadMysqlReadOnly(client); err != nil { + return err + } + + return nil +} + +func (g *MysqlGenerator) loadMysqlMaster(client *cdb.Client) error { + request := cdb.NewDescribeDBInstancesRequest() + var instanceTypeMaster uint64 = 1 + request.InstanceTypes = []*uint64{&instanceTypeMaster} + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*cdb.InstanceInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeDBInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.Items...) + if len(response.Response.Items) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_mysql_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} + +func (g *MysqlGenerator) loadMysqlReadOnly(client *cdb.Client) error { + request := cdb.NewDescribeDBInstancesRequest() + var instanceTypeMaster uint64 = 3 + request.InstanceTypes = []*uint64{&instanceTypeMaster} + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*cdb.InstanceInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeDBInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.Items...) + if len(response.Response.Items) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_mysql_readonly_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} + +func (g *MysqlGenerator) PostConvertHook() error { + for i, resource := range g.Resources { + if resource.InstanceInfo.Type == "tencentcloud_mysql_instance" { + delete(resource.Item, "pay_type") + delete(resource.Item, "period") + } + + if resource.InstanceInfo.Type != "tencentcloud_mysql_readonly_instance" { + if masterID, exist := resource.InstanceState.Attributes["master_instance_id"]; exist { + for _, r := range g.Resources { + if r.InstanceInfo.Type != "tencentcloud_mysql_instance" { + continue + } + if masterID == r.InstanceState.Attributes["id"] { + g.Resources[i].Item["master_instance_id"] = "${tencentcloud_mysql_instance." + r.ResourceName + ".id}" + } + } + } + } + } + + return nil +} diff --git a/providers/tencentcloud/redis.go b/providers/tencentcloud/redis.go new file mode 100755 index 000000000..73e1550e0 --- /dev/null +++ b/providers/tencentcloud/redis.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + redis "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/redis/v20180412" +) + +type RedisGenerator struct { + TencentCloudService +} + +func (g *RedisGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := redis.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := redis.NewDescribeInstancesRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*redis.InstanceSet, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeInstances(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.InstanceSet...) + if len(response.Response.InstanceSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.InstanceId, + *instance.InstanceName+"_"+*instance.InstanceId, + "tencentcloud_redis_instance", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/scf.go b/providers/tencentcloud/scf.go new file mode 100755 index 000000000..09b4b4235 --- /dev/null +++ b/providers/tencentcloud/scf.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + scf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf/v20180416" +) + +type ScfGenerator struct { + TencentCloudService +} + +func (g *ScfGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := scf.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := scf.NewListFunctionsRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*scf.Function, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.ListFunctions(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.Functions...) + if len(response.Response.Functions) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.Namespace+"+"+*instance.FunctionName, + *instance.Namespace+"_"+*instance.FunctionName, + "tencentcloud_scf_function", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/security_group.go b/providers/tencentcloud/security_group.go new file mode 100755 index 000000000..470753524 --- /dev/null +++ b/providers/tencentcloud/security_group.go @@ -0,0 +1,76 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" +) + +type SecurityGroupGenerator struct { + TencentCloudService +} + +func (g *SecurityGroupGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := vpc.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := vpc.NewDescribeSecurityGroupsRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*vpc.SecurityGroup, 0) + + for { + offsetString := fmt.Sprintf("%d", offset) + limitString := fmt.Sprintf("%d", pageSize) + request.Offset = &offsetString + request.Limit = &limitString + response, err := client.DescribeSecurityGroups(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.SecurityGroupSet...) + if len(response.Response.SecurityGroupSet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.SecurityGroupId, + *instance.SecurityGroupName+"_"+*instance.SecurityGroupId, + "tencentcloud_security_group", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/ssl.go b/providers/tencentcloud/ssl.go new file mode 100755 index 000000000..6741989ef --- /dev/null +++ b/providers/tencentcloud/ssl.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" +) + +type SslGenerator struct { + TencentCloudService +} + +func (g *SslGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := ssl.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := ssl.NewDescribeCertificatesRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*ssl.Certificates, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeCertificates(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.Certificates...) + if len(response.Response.Certificates) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.CertificateId, + *instance.CertificateId, + "tencentcloud_ssl_certificate", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/subnet.go b/providers/tencentcloud/subnet.go new file mode 100755 index 000000000..2ba943717 --- /dev/null +++ b/providers/tencentcloud/subnet.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" +) + +type SubnetGenerator struct { + TencentCloudService +} + +func (g *SubnetGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := vpc.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := vpc.NewDescribeSubnetsRequest() + offset := 0 + pageSize := 50 + allSubnets := make([]*vpc.Subnet, 0) + + for { + offsetString := strconv.Itoa(offset) + limitString := strconv.Itoa(pageSize) + request.Offset = &offsetString + request.Limit = &limitString + response, err := client.DescribeSubnets(request) + if err != nil { + return err + } + + allSubnets = append(allSubnets, response.Response.SubnetSet...) + if len(response.Response.SubnetSet) < pageSize { + break + } + offset += pageSize + } + + for _, subnet := range allSubnets { + resource := terraformutils.NewResource( + *subnet.SubnetId, + *subnet.SubnetName+"_"+*subnet.SubnetId, + "tencentcloud_subnet", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/tcaplus.go b/providers/tencentcloud/tcaplus.go new file mode 100755 index 000000000..407cbfa57 --- /dev/null +++ b/providers/tencentcloud/tcaplus.go @@ -0,0 +1,77 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + tcaplus "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcaplusdb/v20190823" +) + +type TcaplusGenerator struct { + TencentCloudService +} + +func (g *TcaplusGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := tcaplus.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := tcaplus.NewDescribeClustersRequest() + + var offset int64 = 0 + var pageSize int64 = 50 + allInstances := make([]*tcaplus.ClusterInfo, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeClusters(request) + if err != nil { + sdkErr, ok := err.(*errors.TencentCloudSDKError) + if ok && sdkErr.Code == "UnsupportedRegion" { + return nil + } + return err + } + + allInstances = append(allInstances, response.Response.Clusters...) + if len(response.Response.Clusters) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.ClusterId, + *instance.ClusterName+"_"+*instance.ClusterId, + "tencentcloud_tcaplus_cluster", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/tencentcloud_provider.go b/providers/tencentcloud/tencentcloud_provider.go new file mode 100755 index 000000000..e67c14b00 --- /dev/null +++ b/providers/tencentcloud/tencentcloud_provider.go @@ -0,0 +1,184 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "errors" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" +) + +type TencentCloudProvider struct { //nolint + terraformutils.Provider + region string + credential common.Credential +} + +func (p *TencentCloudProvider) getCredential() error { + secretID := os.Getenv("TENCENTCLOUD_SECRET_ID") + if secretID == "" { + return errors.New("TENCENTCLOUD_SECRET_ID must be set") + } + secretKey := os.Getenv("TENCENTCLOUD_SECRET_KEY") + if secretKey == "" { + return errors.New("TENCENTCLOUD_SECRET_KEY must be set") + } + token := os.Getenv("TENCENTCLOUD_SECURITY_TOKEN") + + p.credential = common.Credential{ + SecretId: secretID, + SecretKey: secretKey, + Token: token, + } + return nil +} + +func (p *TencentCloudProvider) GetName() string { + return "tencentcloud" +} + +func (p *TencentCloudProvider) Init(args []string) error { + err := p.getCredential() + if err != nil { + return err + } + p.region = args[0] + return nil +} + +func (p *TencentCloudProvider) InitService(serviceName string, verbose bool) error { + var isSupported bool + if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported { + return errors.New("tencentcloud: " + serviceName + " not supported service") + } + p.Service = p.GetSupportedService()[serviceName] + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "region": p.region, + "credential": p.credential, + }) + return nil +} + +func (p *TencentCloudProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "cvm": &CvmGenerator{}, + "vpc": &VpcGenerator{}, + "subnet": &SubnetGenerator{}, + "cdn": &CdnGenerator{}, + "as": &AsGenerator{}, + "clb": &ClbGenerator{}, + "cos": &CosGenerator{}, + "key_pair": &KeyPairGenerator{}, + "security_group": &SecurityGroupGenerator{}, + "cbs": &CbsGenerator{}, + "cfs": &CfsGenerator{}, + "elasticsearch": &EsGenerator{}, + "gaap": &GaapGenerator{}, + "mongodb": &MongodbGenerator{}, + "mysql": &MysqlGenerator{}, + "redis": &RedisGenerator{}, + "ssl": &SslGenerator{}, + "scf": &ScfGenerator{}, + "tcaplus": &TcaplusGenerator{}, + "vpn": &VpnGenerator{}, + } +} + +func (p *TencentCloudProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{ + "cvm": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + "security_group": []string{"security_groups", "id"}, + "key_pair": []string{"key_name", "id"}, + }, + "subnet": { + "vpc": []string{"vpc_id", "id"}, + }, + "as": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_ids", "id"}, + "clb": []string{"forward_balancer_ids", "id"}, + }, + "clb": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + "security_group": []string{"security_groups", "id"}, + }, + "cfs": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, + "elasticsearch": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, + "mongodb": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, + "mysql": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + "security_group": []string{"security_groups", "id"}, + }, + "redis": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, + "scf": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + "cos": []string{"cos_bucket_name", "id"}, + }, + "tcaplus": { + "vpc": []string{"vpc_id", "id"}, + "subnet": []string{"subnet_id", "id"}, + }, + "vpn": { + "vpc": []string{"vpc_id", "id"}, + }, + } +} + +func (p *TencentCloudProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + p.GetName(): map[string]interface{}{ + "version": providerwrapper.GetProviderVersion(p.GetName()), + }, + }, + } +} + +func NewTencentCloudClientProfile() *profile.ClientProfile { + cpf := profile.NewClientProfile() + + // all request use method POST + cpf.HttpProfile.ReqMethod = "POST" + // request timeout + cpf.HttpProfile.ReqTimeout = 300 + // default language + cpf.Language = "en-US" + + return cpf +} diff --git a/providers/tencentcloud/tencentcloud_service.go b/providers/tencentcloud/tencentcloud_service.go new file mode 100755 index 000000000..0ee08c22a --- /dev/null +++ b/providers/tencentcloud/tencentcloud_service.go @@ -0,0 +1,21 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import "github.com/GoogleCloudPlatform/terraformer/terraformutils" + +type TencentCloudService struct { //nolint + terraformutils.Service +} diff --git a/providers/tencentcloud/vpc.go b/providers/tencentcloud/vpc.go new file mode 100755 index 000000000..da036e5d6 --- /dev/null +++ b/providers/tencentcloud/vpc.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "strconv" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" +) + +type VpcGenerator struct { + TencentCloudService +} + +func (g *VpcGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := vpc.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := vpc.NewDescribeVpcsRequest() + offset := 0 + pageSize := 50 + allVpcs := make([]*vpc.Vpc, 0) + + for { + offsetString := strconv.Itoa(offset) + limitString := strconv.Itoa(pageSize) + request.Offset = &offsetString + request.Limit = &limitString + response, err := client.DescribeVpcs(request) + if err != nil { + return err + } + + allVpcs = append(allVpcs, response.Response.VpcSet...) + if len(response.Response.VpcSet) < pageSize { + break + } + offset += pageSize + } + + for _, vpcInstance := range allVpcs { + resource := terraformutils.NewResource( + *vpcInstance.VpcId, + *vpcInstance.VpcName+"_"+*vpcInstance.VpcId, + "tencentcloud_vpc", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/tencentcloud/vpn.go b/providers/tencentcloud/vpn.go new file mode 100755 index 000000000..33d4c5175 --- /dev/null +++ b/providers/tencentcloud/vpn.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tencentcloud + +import ( + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" +) + +type VpnGenerator struct { + TencentCloudService +} + +func (g *VpnGenerator) InitResources() error { + args := g.GetArgs() + region := args["region"].(string) + credential := args["credential"].(common.Credential) + profile := NewTencentCloudClientProfile() + client, err := vpc.NewClient(&credential, region, profile) + if err != nil { + return err + } + + request := vpc.NewDescribeVpnGatewaysRequest() + + var offset uint64 = 0 + var pageSize uint64 = 50 + allInstances := make([]*vpc.VpnGateway, 0) + + for { + request.Offset = &offset + request.Limit = &pageSize + response, err := client.DescribeVpnGateways(request) + if err != nil { + return err + } + + allInstances = append(allInstances, response.Response.VpnGatewaySet...) + if len(response.Response.VpnGatewaySet) < int(pageSize) { + break + } + offset += pageSize + } + + for _, instance := range allInstances { + resource := terraformutils.NewResource( + *instance.VpnGatewayId, + *instance.VpnGatewayName+"_"+*instance.VpnGatewayId, + "tencentcloud_vpn_gateway", + "tencentcloud", + map[string]string{}, + []string{}, + map[string]interface{}{}, + ) + g.Resources = append(g.Resources, resource) + } + + return nil +} diff --git a/providers/vault/vault_provider.go b/providers/vault/vault_provider.go new file mode 100644 index 000000000..2f560fff3 --- /dev/null +++ b/providers/vault/vault_provider.go @@ -0,0 +1,101 @@ +package vault + +import ( + "errors" + "fmt" + "os" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/zclconf/go-cty/cty" +) + +type Provider struct { + terraformutils.Provider + token string + address string +} + +func (p *Provider) Init(args []string) error { + + if address := os.Getenv("VAULT_ADDR"); address != "" { + p.address = os.Getenv("VAULT_ADDR") + } + + if token := os.Getenv("VAULT_TOKEN"); token != "" { + p.token = os.Getenv("VAULT_TOKEN") + } + + if len(args) > 0 && args[0] != "" { + p.address = args[0] + } + + if len(args) > 1 && args[1] != "" { + p.token = args[1] + } + + return nil +} + +func (p *Provider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "token": cty.StringVal(p.token), + "address": cty.StringVal(p.address), + }) +} + +func (p *Provider) GetName() string { + return "vault" +} + +func (p *Provider) InitService(serviceName string, verbose bool) error { + if service, ok := p.GetSupportedService()[serviceName]; ok { + p.Service = service + p.Service.SetName(serviceName) + p.Service.SetVerbose(verbose) + p.Service.SetProviderName(p.GetName()) + p.Service.SetArgs(map[string]interface{}{ + "token": p.token, + "address": p.address, + }) + if err := service.(*ServiceGenerator).setVaultClient(); err != nil { + return err + } + return nil + } + return errors.New(p.GetName() + ": " + serviceName + " not supported service") +} + +func getSupportedMountServices() map[string]terraformutils.ServiceGenerator { + services := make(map[string]terraformutils.ServiceGenerator) + mapping := map[string][]string{ + "secret_backend": {"ad", "aws", "azure", "consul", "gcp", "nomad", "pki", "rabbitmq", "terraform_cloud"}, + "secret_backend_role": {"ad", "aws", "azure", "consul", "database", "pki", "rabbitmq", "ssh"}, + "auth_backend": {"gcp", "github", "jwt", "ldap", "okta"}, + "auth_backend_role": {"alicloud", "approle", "aws", "azure", "cert", "gcp", "jwt", "kubernetes", "token"}, + "auth_backend_user": {"ldap", "okta"}, + "auth_backend_group": {"ldap", "okta"}, + } + for resource, mountTypes := range mapping { + for _, mountType := range mountTypes { + services[fmt.Sprintf("%s_%s", mountType, resource)] = + &ServiceGenerator{mountType: mountType, resource: resource} + } + } + return services +} + +func (p *Provider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + generators := getSupportedMountServices() + generators["policy"] = &ServiceGenerator{resource: "policy"} + generators["mount"] = &ServiceGenerator{resource: "mount"} + generators["generic_secret"] = &ServiceGenerator{resource: "generic_secret", mountType: "kv"} + return generators +} + +func (Provider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (Provider) GetProviderData(_ ...string) map[string]interface{} { + return map[string]interface{}{} +} diff --git a/providers/vault/vault_service_generator.go b/providers/vault/vault_service_generator.go new file mode 100644 index 000000000..502d31c59 --- /dev/null +++ b/providers/vault/vault_service_generator.go @@ -0,0 +1,287 @@ +package vault + +import ( + "errors" + "fmt" + "log" + "regexp" + "sort" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + vault "github.com/hashicorp/vault/api" +) + +type ServiceGenerator struct { //nolint + terraformutils.Service + client *vault.Client + mountType string + resource string +} + +func (g *ServiceGenerator) setVaultClient() error { + client, err := vault.NewClient(&vault.Config{Address: g.Args["address"].(string)}) + if err != nil { + return err + } + if g.Args["token"] != "" { + client.SetToken(g.Args["token"].(string)) + } + g.client = client + return nil +} + +func (g *ServiceGenerator) InitResources() error { + switch g.resource { + case "secret_backend": + return g.createSecretBackendResources() + case "secret_backend_role": + return g.createSecretBackendRoleResources() + case "auth_backend": + return g.createAuthBackendResources() + case "auth_backend_role": + return g.createAuthBackendEntityResources("role", "role") + case "auth_backend_user": + return g.createAuthBackendEntityResources("users", "user") + case "auth_backend_group": + return g.createAuthBackendEntityResources("groups", "group") + case "policy": + return g.createPolicyResources() + case "generic_secret": + return g.createGenericSecretResources() + case "mount": + return g.createMountResources() + default: + return errors.New("unsupported service type. shouldn't ever reach here") + } +} + +func (g *ServiceGenerator) createSecretBackendResources() error { + mounts, err := g.mountsByType() + if err != nil { + return err + } + for _, mount := range mounts { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + mount, + mount, + fmt.Sprintf("vault_%s_secret_backend", g.mountType), + g.ProviderName, + []string{})) + } + return nil +} + +func (g *ServiceGenerator) createSecretBackendRoleResources() error { + mounts, err := g.mountsByType() + if err != nil { + return err + } + for _, mount := range mounts { + path := fmt.Sprintf("%s/roles", mount) + s, err := g.client.Logical().List(path) + if err != nil { + log.Printf("error calling path %s: %s", path, err) + continue + } + if s == nil { + log.Printf("call to %s returned nil result", path) + continue + } + roles, ok := s.Data["keys"] + if !ok { + log.Printf("no keys in call to %s", path) + continue + } + for _, role := range roles.([]interface{}) { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + fmt.Sprintf("%s/roles/%s", mount, role), + fmt.Sprintf("%s_%s", mount, role), + fmt.Sprintf("vault_%s_secret_backend_role", g.mountType), + g.ProviderName, + []string{})) + } + } + return nil +} + +func (g *ServiceGenerator) mountsByType() ([]string, error) { + mounts, err := g.client.Sys().ListMounts() + if err != nil { + return nil, err + } + var typeMounts []string + for name, mount := range mounts { + if g.mountType == "" || mount.Type == g.mountType { + id := strings.ReplaceAll(name, "/", "") + typeMounts = append(typeMounts, id) + } + } + return typeMounts, nil +} + +func (g *ServiceGenerator) createAuthBackendResources() error { + backends, err := g.backendsByType() + if err != nil { + return err + } + for _, backend := range backends { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + backend, + backend, + fmt.Sprintf("vault_%s_auth_backend", g.mountType), + g.ProviderName, + []string{})) + } + return nil +} + +func (g *ServiceGenerator) createAuthBackendEntityResources(apiEntity, tfEntity string) error { + backends, err := g.backendsByType() + if err != nil { + return err + } + for _, backend := range backends { + path := fmt.Sprintf("/auth/%s/%s", backend, apiEntity) + s, err := g.client.Logical().List(path) + if err != nil { + log.Printf("error calling path %s: %s", path, err) + continue + } + if s == nil { + log.Printf("call to %s returned nil result", path) + continue + } + names, ok := s.Data["keys"] + if !ok { + log.Printf("no keys in call to %s", path) + continue + } + for _, name := range names.([]interface{}) { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + fmt.Sprintf("auth/%s/%s/%s", backend, apiEntity, name), + fmt.Sprintf("%s_%s", backend, name), + fmt.Sprintf("vault_%s_auth_backend_%s", g.mountType, tfEntity), + g.ProviderName, + []string{})) + } + } + return nil +} + +func (g *ServiceGenerator) backendsByType() ([]string, error) { + authBackends, err := g.client.Sys().ListAuth() + if err != nil { + return nil, err + } + var typeBackends []string + for name, authBackend := range authBackends { + if authBackend.Type != g.mountType { + continue + } + id := strings.ReplaceAll(name, "/", "") + typeBackends = append(typeBackends, id) + } + return typeBackends, nil +} + +func (g *ServiceGenerator) createPolicyResources() error { + policies, err := g.client.Sys().ListPolicies() + if err != nil { + return err + } + for _, policy := range policies { + if policy == "root" { + continue + } + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + policy, + policy, + "vault_policy", + g.ProviderName, + []string{})) + } + return nil +} + +func (g *ServiceGenerator) createGenericSecretResources() error { + mounts, err := g.mountsByType() + if err != nil { + return err + } + for _, mount := range mounts { + path := fmt.Sprintf("%s/", mount) + s, err := g.client.Logical().List(path) + if err != nil { + log.Printf("error calling path %s: %s", path, err) + continue + } + if s == nil { + log.Printf("call to %s returned nil result", path) + continue + } + secrets, ok := s.Data["keys"] + if !ok { + log.Printf("no keys in call to %s", path) + continue + } + for _, secret := range secrets.([]interface{}) { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + fmt.Sprintf("%s/%s", mount, secret), + fmt.Sprintf("%s_%s", mount, secret), + "vault_generic_secret", + g.ProviderName, + []string{})) + } + } + return nil +} + +func (g *ServiceGenerator) createMountResources() error { + mounts, err := g.mountsByType() + if err != nil { + return err + } + for _, mount := range mounts { + g.Resources = append(g.Resources, + terraformutils.NewSimpleResource( + mount, + mount, + "vault_mount", + g.ProviderName, + []string{})) + } + return nil +} + +func (g *ServiceGenerator) PostConvertHook() error { + for _, resource := range g.Resources { + switch resource.InstanceInfo.Type { + case "vault_aws_secret_backend_role": + if policyDocument, ok := resource.Item["policy_document"]; ok { + // borrowed from providers/aws/aws_service.go + sanitizedPolicy := regexp.MustCompile(`(\${[0-9A-Za-z:]+})`). + ReplaceAllString(policyDocument.(string), "$$$1") + resource.Item["policy_document"] = fmt.Sprintf(`< 0 { + p.Resources = map[*Resource]bool{} + p.resourceToProvider = map[*Resource]ProviderGenerator{} + for provider := range p.Providers { + resources := provider.GetService().GetResources() + log.Printf("Filtered number of resources for service %s: %d", p.providerToService[provider], len(provider.GetService().GetResources())) + for i := range resources { + resource := resources[i] + p.Resources[&resource] = true + p.resourceToProvider[&resource] = provider + } + } + } else if !isCleanup { + for provider := range p.Providers { + resources := provider.GetService().GetResources() + log.Printf("Number of resources for service %s: %d", p.providerToService[provider], len(provider.GetService().GetResources())) + for i := range resources { + resource := resources[i] + p.Resources[&resource] = true + p.resourceToProvider[&resource] = provider + } } } } @@ -162,4 +177,5 @@ func (p *ProvidersMapping) CleanupProviders() { log.Printf("failed run PostConvertHook because of error %s", err) } } + p.ProcessResources(true) } diff --git a/terraformutils/providerwrapper/provider.go b/terraformutils/providerwrapper/provider.go index 1325b6c61..153781d30 100644 --- a/terraformutils/providerwrapper/provider.go +++ b/terraformutils/providerwrapper/provider.go @@ -60,17 +60,20 @@ type ProviderWrapper struct { retrySleepMs int } -func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool, retryOptions ...int) (*ProviderWrapper, error) { - p := &ProviderWrapper{} +func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool, options ...map[string]int) (*ProviderWrapper, error) { + p := &ProviderWrapper{retryCount: 5, retrySleepMs: 300} p.providerName = providerName p.config = providerConfig - if len(retryOptions) == 2 { - p.retryCount = retryOptions[0] - p.retrySleepMs = retryOptions[1] - } else { - p.retryCount = 5 - p.retrySleepMs = 300 + if len(options) > 0 { + retryCount, hasOption := options[0]["retryCount"] + if hasOption { + p.retryCount = retryCount + } + retrySleepMs, hasOption := options[0]["retrySleepMs"] + if hasOption { + p.retrySleepMs = retrySleepMs + } } err := p.initProvider(verbose) @@ -103,7 +106,7 @@ func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[str for k, v := range obj.Block.Attributes { if !v.Optional && !v.Required { if v.Type.IsListType() || v.Type.IsSetType() { - readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+".(.*)") + readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"\\.(.*)") } else { readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"$") } @@ -118,7 +121,11 @@ func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[str func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlock, readOnlyAttributes []string, parent string) []string { for k, v := range block { if len(v.BlockTypes) > 0 { - readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k) + if parent == "-1" { + readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k) + } else { + readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, parent+"\\.[0-9]+\\."+k) + } } fieldCount := 0 for key, l := range v.Attributes { @@ -127,24 +134,24 @@ func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlo switch v.Nesting { case configschema.NestingList: if parent == "-1" { - readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"($|\\.[0-9]|\\.#)") + readOnlyAttributes = append(readOnlyAttributes, "^"+k+"\\.[0-9]+\\."+key+"($|\\.[0-9]+|\\.#)") } else { - readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"$") + readOnlyAttributes = append(readOnlyAttributes, "^"+parent+"\\.(.*)\\."+key+"$") } case configschema.NestingSet: if parent == "-1" { - readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"$") + readOnlyAttributes = append(readOnlyAttributes, "^"+k+"\\.[0-9]+\\."+key+"$") } else { - readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"($|\\.(.*))") + readOnlyAttributes = append(readOnlyAttributes, "^"+parent+"\\.(.*)\\."+key+"($|\\.(.*))") } case configschema.NestingMap: - readOnlyAttributes = append(readOnlyAttributes, parent+"."+key) + readOnlyAttributes = append(readOnlyAttributes, parent+"\\."+key) default: - readOnlyAttributes = append(readOnlyAttributes, parent+"."+key+"$") + readOnlyAttributes = append(readOnlyAttributes, parent+"\\."+key+"$") } } } - if fieldCount == len(v.Block.Attributes) && fieldCount > 0 { + if fieldCount == len(v.Block.Attributes) && fieldCount > 0 && len(v.BlockTypes) == 0 { readOnlyAttributes = append(readOnlyAttributes, "^"+k) } } @@ -167,7 +174,8 @@ func (p *ProviderWrapper) Refresh(info *terraform.InstanceInfo, state *terraform Private: []byte{}, }) if resp.Diagnostics.HasErrors() { - log.Printf("WARN: Fail read resource from provider, wait %dms before retry, error is: %s\n", p.retrySleepMs, resp.Diagnostics.ErrWithWarnings()) + log.Println(resp.Diagnostics.Err()) + log.Printf("WARN: Fail read resource from provider, wait %dms before retry\n", p.retrySleepMs) time.Sleep(time.Duration(p.retrySleepMs) * time.Millisecond) continue } else { @@ -252,9 +260,9 @@ func getProviderFileName(providerName string) (string, error) { if defaultDataDir == "" { defaultDataDir = DefaultDataDir } - providerFilePath, err := getProviderFileNameV13(defaultDataDir, providerName) + providerFilePath, err := getProviderFileNameV13andV14(defaultDataDir, providerName) if err != nil || providerFilePath == "" { - providerFilePath, err = getProviderFileNameV13(os.Getenv("HOME")+string(os.PathSeparator)+ + providerFilePath, err = getProviderFileNameV13andV14(os.Getenv("HOME")+string(os.PathSeparator)+ ".terraform.d", providerName) } if err != nil || providerFilePath == "" { @@ -263,13 +271,19 @@ func getProviderFileName(providerName string) (string, error) { return providerFilePath, nil } -func getProviderFileNameV13(prefix, providerName string) (string, error) { - - registryDir := prefix + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + +func getProviderFileNameV13andV14(prefix, providerName string) (string, error) { + // Read terraform v14 file path + registryDir := prefix + string(os.PathSeparator) + "providers" + string(os.PathSeparator) + "registry.terraform.io" providerDirs, err := ioutil.ReadDir(registryDir) if err != nil { - return "", err + // Read terraform v13 file path + registryDir = prefix + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + + "registry.terraform.io" + providerDirs, err = ioutil.ReadDir(registryDir) + if err != nil { + return "", err + } } providerFilePath := "" for _, providerDir := range providerDirs { diff --git a/terraformutils/providerwrapper/provider_test.go b/terraformutils/providerwrapper/provider_test.go new file mode 100644 index 000000000..959bdd6e5 --- /dev/null +++ b/terraformutils/providerwrapper/provider_test.go @@ -0,0 +1,84 @@ +package providerwrapper //nolint + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform/configs/configschema" + "github.com/zclconf/go-cty/cty" +) + +func TestIgnoredAttributes(t *testing.T) { + attributes := map[string]*configschema.Attribute{ + "computed_attribute": { + Type: cty.Number, + Computed: true, + }, + "required_attribute": { + Type: cty.String, + Required: true, + }, + } + + testCases := map[string]struct { + block map[string]*configschema.NestedBlock + ignoredAttributes []string + notIgnoredAttributes []string + }{ + "nesting_set": {map[string]*configschema.NestedBlock{ + "attribute_one": { + Block: configschema.Block{ + Attributes: attributes, + }, + Nesting: configschema.NestingSet, + }, + }, []string{"nesting_set.attribute_one.computed_attribute"}, + []string{"nesting_set.attribute_one.required_attribute"}}, + "nesting_list": {map[string]*configschema.NestedBlock{ + "attribute_one": { + Block: configschema.Block{ + Attributes: map[string]*configschema.Attribute{}, + BlockTypes: map[string]*configschema.NestedBlock{ + "attribute_two_nested": { + Nesting: configschema.NestingList, + Block: configschema.Block{ + Attributes: attributes, + }, + }, + }, + }, + Nesting: configschema.NestingList, + }, + }, []string{"nesting_list.0.attribute_one.0.attribute_two_nested.computed_attribute"}, + []string{"nesting_list.0.attribute_one.0.attribute_two_nested.required_attribute"}}, + } + + for key, tc := range testCases { + t.Run(key, func(t *testing.T) { + provider := ProviderWrapper{} + readOnlyAttributes := provider.readObjBlocks(tc.block, []string{}, key) + for _, attr := range tc.ignoredAttributes { + if ignored := isAttributeIgnored(attr, readOnlyAttributes); !ignored { + t.Errorf("attribute \"%s\" was not ignored. Pattern list: %s", attr, readOnlyAttributes) + } + } + + for _, attr := range tc.notIgnoredAttributes { + if ignored := isAttributeIgnored(attr, readOnlyAttributes); ignored { + t.Errorf("attribute \"%s\" was ignored. Pattern list: %s", attr, readOnlyAttributes) + } + } + }) + } +} + +func isAttributeIgnored(name string, patterns []string) bool { + ignored := false + for _, pattern := range patterns { + if match, _ := regexp.MatchString(pattern, name); match { + ignored = true + break + } + } + return ignored +} diff --git a/terraformutils/resource.go b/terraformutils/resource.go index fc7450546..04766a694 100644 --- a/terraformutils/resource.go +++ b/terraformutils/resource.go @@ -37,6 +37,7 @@ type Resource struct { AllowEmptyValues []string `json:",omitempty"` AdditionalFields map[string]interface{} `json:",omitempty"` SlowQueryRequired bool + DataFiles map[string][]byte } type ApplicableFilter interface { @@ -55,9 +56,16 @@ func (rf *ResourceFilter) Filter(resource Resource) bool { return true } var vals []interface{} - if rf.FieldPath == "id" { + switch { + case rf.FieldPath == "id": vals = []interface{}{resource.InstanceState.ID} - } else { + case rf.AcceptableValues == nil: + var hasField = WalkAndCheckField(rf.FieldPath, resource.InstanceState.Attributes) + if hasField { + return true + } + return WalkAndCheckField(rf.FieldPath, resource.Item) + default: vals = WalkAndGet(rf.FieldPath, resource.InstanceState.Attributes) if len(vals) == 0 { vals = WalkAndGet(rf.FieldPath, resource.Item) diff --git a/terraformutils/service.go b/terraformutils/service.go index 439e3f9fc..afcb5c9ad 100644 --- a/terraformutils/service.go +++ b/terraformutils/service.go @@ -71,7 +71,7 @@ func (s *Service) ParseFilters(rawFilters []string) { func (s *Service) ParseFilter(rawFilter string) []ResourceFilter { var filters []ResourceFilter - if len(strings.Split(rawFilter, "=")) == 2 { + if !strings.HasPrefix(rawFilter, "Name=") && len(strings.Split(rawFilter, "=")) == 2 { parts := strings.Split(rawFilter, "=") serviceName, resourcesID := parts[0], parts[1] filters = append(filters, ResourceFilter{ @@ -81,18 +81,23 @@ func (s *Service) ParseFilter(rawFilter string) []ResourceFilter { }) } else { parts := strings.Split(rawFilter, ";") - if len(parts) != 2 && len(parts) != 3 { + if !((len(parts) == 1 && strings.HasPrefix(rawFilter, "Name=")) || len(parts) == 2 || len(parts) == 3) { log.Print("Invalid filter: " + rawFilter) return filters } var ServiceNamePart string var FieldPathPart string var AcceptableValuesPart string - if len(parts) == 2 { + switch len(parts) { + case 1: + ServiceNamePart = "" + FieldPathPart = parts[0] + AcceptableValuesPart = "" + case 2: ServiceNamePart = "" FieldPathPart = parts[0] AcceptableValuesPart = parts[1] - } else { + default: ServiceNamePart = strings.TrimPrefix(parts[0], "Type=") FieldPathPart = parts[1] AcceptableValuesPart = parts[2] diff --git a/terraformutils/service_test.go b/terraformutils/service_test.go index 25b4f781c..1f76663ea 100644 --- a/terraformutils/service_test.go +++ b/terraformutils/service_test.go @@ -109,3 +109,31 @@ func TestServiceAttributeCleanupWithFilter(t *testing.T) { t.Errorf("failed to cleanup") } } + +func TestServiceAttributeNameOnlyCleanupWithFilter(t *testing.T) { + service := Service{ + Resources: []Resource{ + { + InstanceInfo: &terraform.InstanceInfo{ + Type: "aws_vpc", + }, + InstanceState: &terraform.InstanceState{ + ID: "vpc1", + }, + Item: mapI("tags", mapI("Abc", nil))}, + { + InstanceInfo: &terraform.InstanceInfo{ + Type: "aws_vpc", + }, + InstanceState: &terraform.InstanceState{ + ID: "vpc2", + }, + Item: mapI("tags", mapI("Name", "default"))}}, + } + service.ParseFilters([]string{"Name=tags.Abc"}) + service.PostRefreshCleanup() + + if !reflect.DeepEqual(len(service.Resources), 1) { + t.Errorf("failed to cleanup") + } +} diff --git a/terraformutils/terraformoutput/hcl.go b/terraformutils/terraformoutput/hcl.go index ef0c58085..cef39dcf3 100644 --- a/terraformutils/terraformoutput/hcl.go +++ b/terraformutils/terraformoutput/hcl.go @@ -33,9 +33,9 @@ func OutputHclFiles(resources []terraformutils.Resource, provider terraformutils providerData := provider.GetProviderData() providerData["terraform"] = map[string]interface{}{ "required_providers": []map[string]interface{}{{ - provider.GetName(): []map[string]interface{}{{ + provider.GetName(): map[string]interface{}{ "version": providerwrapper.GetProviderVersion(provider.GetName()), - }}, + }, }}, } @@ -52,7 +52,7 @@ func OutputHclFiles(resources []terraformutils.Resource, provider terraformutils for i, r := range resources { outputState := map[string]*terraform.OutputState{} outputsByResource[r.InstanceInfo.Type+"_"+r.ResourceName+"_"+r.GetIDKey()] = map[string]interface{}{ - "value": r.InstanceInfo.Type + "." + r.ResourceName + "." + r.GetIDKey(), + "value": "${" + r.InstanceInfo.Type + "." + r.ResourceName + "." + r.GetIDKey() + "}", } outputState[r.InstanceInfo.Type+"_"+r.ResourceName+"_"+r.GetIDKey()] = &terraform.OutputState{ Type: "string", @@ -68,7 +68,7 @@ func OutputHclFiles(resources []terraformutils.Resource, provider terraformutils } linkKey := r.InstanceInfo.Type + "_" + r.ResourceName + "_" + key outputsByResource[linkKey] = map[string]interface{}{ - "value": r.InstanceInfo.Type + "." + r.ResourceName + "." + key, + "value": "${" + r.InstanceInfo.Type + "." + r.ResourceName + "." + key + "}", } outputState[linkKey] = &terraform.OutputState{ Type: "string", @@ -112,6 +112,21 @@ func OutputHclFiles(resources []terraformutils.Resource, provider terraformutils } func printFile(v []terraformutils.Resource, fileName, path, output string) error { + for _, res := range v { + if res.DataFiles == nil { + continue + } + for fileName, content := range res.DataFiles { + if err := os.MkdirAll(path+"/data/", os.ModePerm); err != nil { + return err + } + err := ioutil.WriteFile(path+"/data/"+fileName, content, os.ModePerm) + if err != nil { + return err + } + } + } + tfFile, err := terraformutils.HclPrintResource(v, map[string]interface{}{}, output) if err != nil { return err @@ -120,6 +135,7 @@ func printFile(v []terraformutils.Resource, fileName, path, output string) error if err != nil { return err } + return nil } diff --git a/terraformutils/walk.go b/terraformutils/walk.go index 4b162c4f8..f4382cd7d 100644 --- a/terraformutils/walk.go +++ b/terraformutils/walk.go @@ -15,13 +15,18 @@ package terraformutils import ( + "fmt" "reflect" "strings" ) func WalkAndGet(path string, data interface{}) []interface{} { - pathSegments := strings.Split(path, ".") - return walkAndGet(pathSegments, data) + _, values := walkAndGet(path, data) + return values +} +func WalkAndCheckField(path string, data interface{}) bool { + hasField, _ := walkAndGet(path, data) + return hasField } func WalkAndOverride(path, oldValue, newValue string, data interface{}) { @@ -29,44 +34,52 @@ func WalkAndOverride(path, oldValue, newValue string, data interface{}) { walkAndOverride(pathSegments, oldValue, newValue, data) } -func walkAndGet(pathSegments []string, data interface{}) []interface{} { +func walkAndGet(path string, data interface{}) (bool, []interface{}) { val := reflect.ValueOf(data) - switch { - case isArray(val.Interface()): + + if data == nil { + if path == "" { + return true, []interface{}{} + } + return false, []interface{}{} + } + + if isArray(val.Interface()) { var arrayValues []interface{} for i := 0; i < val.Len(); i++ { - arrayValues = append(arrayValues, walkAndGet(pathSegments, val.Index(i).Interface())...) - } - return arrayValues - case len(pathSegments) == 1: - if val.Kind() == reflect.Map { - for _, e := range val.MapKeys() { - v := val.MapIndex(e) - if e.String() == pathSegments[0] { - switch { - case isArray(v.Interface()): - return v.Interface().([]interface{}) - case isStringArray(v.Interface()): - return v.Interface().([]interface{}) - default: - return []interface{}{v.Interface()} - } - } + foundField, fieldValue := walkAndGet(path, val.Index(i).Interface()) + if foundField { + arrayValues = append(arrayValues, fieldValue...) } } - return []interface{}{} - default: - if val.Kind() == reflect.Map { - for _, e := range val.MapKeys() { - v := val.MapIndex(e) - if e.String() == pathSegments[0] { - return walkAndGet(pathSegments[1:], v.Interface()) + return len(arrayValues) > 0, arrayValues + } + + if val.Kind() == reflect.Map { + for _, e := range val.MapKeys() { + v := val.MapIndex(e) + pathFirstElement := strings.SplitN(path, ".", 2) + if e.String() == pathFirstElement[0] { + var pathReminder = "" + if len(pathFirstElement) > 1 { + pathReminder = pathFirstElement[1] } + hasField, value := walkAndGet(pathReminder, v.Interface()) + if !hasField { + hasField, value = walkAndGet(path, v.Interface()) + } + return hasField, value + } else if e.String() == path { + return walkAndGet("", v.Interface()) } - return []interface{}{} } - return []interface{}{} } + + if val.Kind() == reflect.String && path == "" { + return true, []interface{}{val.Interface()} + } + + return false, []interface{}{} } func walkAndOverride(pathSegments []string, oldValue, newValue string, data interface{}) { @@ -97,7 +110,7 @@ func walkAndOverride(pathSegments []string, oldValue, newValue string, data inte valss[idx] = newValue } } - case oldValue == v.Interface().(string): + case oldValue == fmt.Sprint(v.Interface()): val.Interface().(map[string]interface{})[pathSegments[0]] = newValue } } diff --git a/terraformutils/walk_test.go b/terraformutils/walk_test.go index 0d8b32d0f..0f39eb8d4 100644 --- a/terraformutils/walk_test.go +++ b/terraformutils/walk_test.go @@ -58,6 +58,19 @@ func TestNestedWalkAndGet(t *testing.T) { } } +func TestNestedWalkWithDotInKeyAndGet(t *testing.T) { + structure := map[string]map[string]interface{}{ + "attr1": { + "attr2.attr3": "value", + }, + } + value := WalkAndGet("attr1.attr2.attr3", structure) + + if !reflect.DeepEqual(value, []interface{}{"value"}) { + t.Errorf("failed to get value %v", value) + } +} + func TestNestedArrayWalkAndGet(t *testing.T) { structure := mapI("attr1", []interface{}{ mapI("attr2", "value1"), @@ -148,3 +161,23 @@ func TestNestedArrayWalkAndOverride(t *testing.T) { t.Errorf("failed to set value") } } + +func TestEmptyWalkAndCheckField(t *testing.T) { + structure := map[string]interface{}{} + value := WalkAndCheckField("attr1", structure) + + if !reflect.DeepEqual(value, false) { + t.Errorf("failed to get value %v", value) + } +} + +func TestSimpleWalkAndCheckField(t *testing.T) { + structure := map[string]interface{}{ + "attr1": "value", + } + value := WalkAndCheckField("attr1", structure) + + if !reflect.DeepEqual(value, true) { + t.Errorf("failed to get value %v", value) + } +} diff --git a/tests/aws/main.go b/tests/aws/main.go index d30c4a0f5..f555f86c7 100644 --- a/tests/aws/main.go +++ b/tests/aws/main.go @@ -31,8 +31,9 @@ func main() { "import", "aws", "--regions=ap-southeast-1", - "--resources=vpc,sg", + "--resources=ssm", "--profile=personal", + "--verbose", "--compact", "--path-pattern=" + pathPattern, })