diff --git a/README.md b/README.md index 7160b6b2c..07402e825 100644 --- a/README.md +++ b/README.md @@ -9,74 +9,77 @@ A CLI tool that generates `tf`/`json` and `tfstate` files based on existing infrastructure (reverse Terraform). -* Disclaimer: This is not an official Google product -* Created by: Waze SRE +- Disclaimer: This is not an official Google product +- Created by: Waze SRE ![Waze SRE logo](assets/waze-sre-logo.png) # Table of Contents + - [Demo GCP](#demo-gcp) - [Capabilities](#capabilities) - [Installation](#installation) - [Supported Providers](/docs) - * Major Cloud - * [Google Cloud](/docs/gcp.md) - * [AWS](/docs/aws.md) - * [Azure](/docs/azure.md) - * [AliCloud](/docs/alicloud.md) - * [IBM Cloud](/docs/ibmcloud.md) - * Cloud - * [DigitalOcean](/docs/digitalocean.md) - * [Equinix Metal](/docs/equinixmetal.md) - * [Fastly](/docs/fastly.md) - * [Heroku](/docs/heroku.md) - * [LaunchDarkly](/docs/launchdarkly.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) - * [Ionos Cloud](/docs/ionoscloud.md) - * Infrastructure Software - * [Kubernetes](/docs/kubernetes.md) - * [OctopusDeploy](/docs/octopus.md) - * [RabbitMQ](/docs/rabbitmq.md) - * Network - * [Cloudflare](/docs/cloudflare.md) - * [Myrasec](/docs/myrasec.md) - * [PAN-OS](/docs/panos.md) - * VCS - * [Azure DevOps](/docs/azuredevops.md) - * [GitHub](/docs/github.md) - * [Gitlab](/docs/gitlab.md) - * Monitoring & System Management - * [Datadog](/docs/datadog.md) - * [New Relic](/docs/relic.md) - * [Mackerel](/docs/mackerel.md) - * [PagerDuty](/docs/pagerduty.md) - * [Opsgenie](/docs/opsgenie.md) - * [Honeycomb.io](/docs/honeycombio.md) - * [Opal](/docs/opal.md) - * Community - * [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) - * [Auth0](/docs/auth0.md) - * [AzureAD](/docs/azuread.md) + - Major Cloud + - [Google Cloud](/docs/gcp.md) + - [AWS](/docs/aws.md) + - [Azure](/docs/azure.md) + - [AliCloud](/docs/alicloud.md) + - [IBM Cloud](/docs/ibmcloud.md) + - Cloud + - [DigitalOcean](/docs/digitalocean.md) + - [Equinix Metal](/docs/equinixmetal.md) + - [Fastly](/docs/fastly.md) + - [Heroku](/docs/heroku.md) + - [LaunchDarkly](/docs/launchdarkly.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) + - [Ionos Cloud](/docs/ionoscloud.md) + - Infrastructure Software + - [Kubernetes](/docs/kubernetes.md) + - [OctopusDeploy](/docs/octopus.md) + - [RabbitMQ](/docs/rabbitmq.md) + - Network + - [Cloudflare](/docs/cloudflare.md) + - [Myrasec](/docs/myrasec.md) + - [PAN-OS](/docs/panos.md) + - VCS + - [Azure DevOps](/docs/azuredevops.md) + - [GitHub](/docs/github.md) + - [Gitlab](/docs/gitlab.md) + - Monitoring & System Management + - [Datadog](/docs/datadog.md) + - [New Relic](/docs/relic.md) + - [Mackerel](/docs/mackerel.md) + - [PagerDuty](/docs/pagerduty.md) + - [Opsgenie](/docs/opsgenie.md) + - [Honeycomb.io](/docs/honeycombio.md) + - [Squadcast](/docs/squadcast.md) + - [Opal](/docs/opal.md) + - Community + - [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) + - [Auth0](/docs/auth0.md) + - [AzureAD](/docs/azuread.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 @@ -91,6 +94,7 @@ A CLI tool that generates `tf`/`json` and `tfstate` files based on existing infr Terraformer uses Terraform providers and is designed to easily support newly added resources. To upgrade resources with new fields, all you need to do is upgrade the relevant Terraform providers. + ``` Import current state to Terraform configuration from a provider @@ -121,6 +125,7 @@ Flags: Use " import [provider] [command] --help" for more information about a command. ``` + #### Permissions The tool requires read-only permissions to list service resources. @@ -136,15 +141,19 @@ 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`. ##### Migration state version + For terraform >= 0.13, you can use `replace-provider` to migrate state from previous versions. Example usage: + ``` terraform state replace-provider -auto-approve "registry.terraform.io/-/aws" "hashicorp/aws" ``` @@ -160,6 +169,7 @@ Example usage: ``` terraformer import aws --resources=vpc,subnet --filter=vpc=myvpcid --regions=eu-west-1 ``` + 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 @@ -171,6 +181,7 @@ 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 @@ -182,6 +193,7 @@ 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 @@ -210,6 +222,7 @@ Terraformer by default separates each resource into a file, which is put into a The default path for resource files is `{output}/{provider}/{service}/{resource}.tf` and can vary for each provider. It's possible to adjust the generated structure by: + 1. Using `--compact` parameter to group resource files within a single service into one `resources.tf` file 2. Adjusting the `--path-pattern` parameter and passing e.g. `--path-pattern {output}/{provider}/` to generate resources for all services in one directory @@ -222,6 +235,7 @@ Both Terraformer and a Terraform provider plugin need to be installed. #### Terraformer **From 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`. @@ -229,36 +243,43 @@ Both Terraformer and a Terraform provider plugin need to be installed. **From releases** This installs all providers, set `PROVIDER` to one of `google`, `aws` or `kubernetes` if you only need one. -* Linux +- Linux + ``` export PROVIDER=all curl -LO "https://github.com/GoogleCloudPlatform/terraformer/releases/download/$(curl -s https://api.github.com/repos/GoogleCloudPlatform/terraformer/releases/latest | grep tag_name | cut -d '"' -f 4)/terraformer-${PROVIDER}-linux-amd64" chmod +x terraformer-${PROVIDER}-linux-amd64 sudo mv terraformer-${PROVIDER}-linux-amd64 /usr/local/bin/terraformer ``` -* MacOS + +- MacOS + ``` export PROVIDER=all curl -LO "https://github.com/GoogleCloudPlatform/terraformer/releases/download/$(curl -s https://api.github.com/repos/GoogleCloudPlatform/terraformer/releases/latest | grep tag_name | cut -d '"' -f 4)/terraformer-${PROVIDER}-darwin-amd64" chmod +x terraformer-${PROVIDER}-darwin-amd64 sudo mv terraformer-${PROVIDER}-darwin-amd64 /usr/local/bin/terraformer ``` -* Windows + +- Windows + 1. Install Terraform - https://www.terraform.io/downloads 2. Download exe file for required provider from here - https://github.com/GoogleCloudPlatform/terraformer/releases 3. Add the exe file path to path variable **From source** + 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,etc}` + `go run build/main.go {google,aws,azure,kubernetes,etc}` #### Terraform Providers -Create a working folder and initialize the Terraform provider plugin. This folder will be where you run Terraformer commands. +Create a working folder and initialize the Terraform provider plugin. This folder will be where you run Terraformer commands. + +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: -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 { required_providers { @@ -273,63 +294,68 @@ terraform { Or, copy your Terraform provider's plugin(s) from the list below to folder `~/.terraform.d/plugins/`, as appropriate. Links to download Terraform provider plugins: -* Major Cloud - * Google Cloud provider >2.11.0 - [here](https://releases.hashicorp.com/terraform-provider-google/) - * AWS provider >2.25.0 - [here](https://releases.hashicorp.com/terraform-provider-aws/) - * Azure provider >1.35.0 - [here](https://releases.hashicorp.com/terraform-provider-azurerm/) - * 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/) - * Heroku provider >2.2.1 - [here](https://releases.hashicorp.com/terraform-provider-heroku/) - * LaunchDarkly provider >=2.1.1 - [here](https://releases.hashicorp.com/terraform-provider-launchdarkly/) - * Linode provider >1.8.0 - [here](https://releases.hashicorp.com/terraform-provider-linode/) - * 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/) - * Ionoscloud provider >6.3.3 - [here](https://github.com/ionos-cloud/terraform-provider-ionoscloud/releases) -* Infrastructure Software - * Kubernetes provider >=1.9.0 - [here](https://releases.hashicorp.com/terraform-provider-kubernetes/) - * RabbitMQ provider >=1.1.0 - [here](https://releases.hashicorp.com/terraform-provider-rabbitmq/) -* Network - * Myrasec provider >1.44 - [here](https://github.com/Myra-Security-GmbH/terraform-provider-myrasec) - * 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 >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/) - * Honeycomb.io >= 0.10.0 - [here](https://github.com/honeycombio/terraform-provider-honeycombio/releases) - * Opal >= 0.0.2 - [here](https://github.com/opalsecurity/terraform-provider-opal/releases) -* 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/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) - * Auth0 provider - [here](https://github.com/alexkappa/terraform-provider-auth0) - * AzureAD provider - [here](https://github.com/hashicorp/terraform-provider-azuread) + +- Major Cloud + - Google Cloud provider >2.11.0 - [here](https://releases.hashicorp.com/terraform-provider-google/) + - AWS provider >2.25.0 - [here](https://releases.hashicorp.com/terraform-provider-aws/) + - Azure provider >1.35.0 - [here](https://releases.hashicorp.com/terraform-provider-azurerm/) + - 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/) + - Heroku provider >2.2.1 - [here](https://releases.hashicorp.com/terraform-provider-heroku/) + - LaunchDarkly provider >=2.1.1 - [here](https://releases.hashicorp.com/terraform-provider-launchdarkly/) + - Linode provider >1.8.0 - [here](https://releases.hashicorp.com/terraform-provider-linode/) + - 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/) + - Ionoscloud provider >6.3.3 - [here](https://github.com/ionos-cloud/terraform-provider-ionoscloud/releases) +- Infrastructure Software + - Kubernetes provider >=1.9.0 - [here](https://releases.hashicorp.com/terraform-provider-kubernetes/) + - RabbitMQ provider >=1.1.0 - [here](https://releases.hashicorp.com/terraform-provider-rabbitmq/) +- Network + - Myrasec provider >1.44 - [here](https://github.com/Myra-Security-GmbH/terraform-provider-myrasec) + - 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 >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/) + _ Honeycomb.io >= 0.10.0 - [here](https://github.com/honeycombio/terraform-provider-honeycombio/releases) + <<<<<<< HEAD + _ Squadcast provider >= 1.0.4 - [here](https://github.com/SquadcastHub/terraform-provider-squadcast) + ======= + _ Opal >= 0.0.2 - [here](https://github.com/opalsecurity/terraform-provider-opal/releases) + > > > > > > > f3e9ae76a6187a4b6954e182e1f2a9297ab096fb +- 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/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) + - Auth0 provider - [here](https://github.com/alexkappa/terraform-provider-auth0) + - AzureAD provider - [here](https://github.com/hashicorp/terraform-provider-azuread) Information on provider plugins: https://www.terraform.io/docs/configuration/providers.html - ## High-Level steps to add new provider - * Initialize provider details in cmd/root.go and create a provider initialization file in the terraformer/cmd folder - * Create a folder under terraformer/providers/ for your provider - * Create two files under this folder - * _provider.go - * _service.go -* Initialize all provider's supported services in _provider.go file -* Create script for each supported service in same folder + +- Initialize provider details in cmd/root.go and create a provider initialization file in the terraformer/cmd folder +- Create a folder under terraformer/providers/ for your provider +- Create two files under this folder + - \_provider.go + - \_service.go +- Initialize all provider's supported services in \_provider.go file +- Create script for each supported service in same folder ## Contributing @@ -375,10 +401,10 @@ go run providers/gcp/gcp_compute_code_generator/*.go ##### Terraformer Benefits -* Simpler to add new providers and resources - already supports AWS, GCP, GitHub, Kubernetes, and Openstack. Terraforming supports only AWS. -* Better support for HCL + tfstate, including updates for Terraform 0.12. -* If a provider adds new attributes to a resource, there is no need change Terraformer code - just update the Terraform provider on your laptop. -* Automatically supports connections between resources in HCL files. +- Simpler to add new providers and resources - already supports AWS, GCP, GitHub, Kubernetes, and Openstack. Terraforming supports only AWS. +- Better support for HCL + tfstate, including updates for Terraform 0.12. +- If a provider adds new attributes to a resource, there is no need change Terraformer code - just update the Terraform provider on your laptop. +- Automatically supports connections between resources in HCL files. ##### Comparison @@ -389,8 +415,8 @@ Terraformer instead uses Terraform provider files for mapping attributes, HCL li Look for S3 support in terraforming here and official S3 support Terraforming lacks full coverage for resources - as an example you can see that 70% of S3 options are not supported: -* 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 +- 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 ## Stargazers over time diff --git a/cmd/provider_cmd_squadcast.go b/cmd/provider_cmd_squadcast.go new file mode 100644 index 000000000..8214ae8b5 --- /dev/null +++ b/cmd/provider_cmd_squadcast.go @@ -0,0 +1,38 @@ +package cmd + +import ( + squadcast_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/squadcast" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdSquadcastImporter(options ImportOptions) *cobra.Command { + var refreshToken, teamName, region, serviceName string + + cmd := &cobra.Command{ + Use: "squadcast", + Short: "Import current state to Terraform configuration from Squadcast", + Long: "Import current state to Terraform configuration from Squadcast", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newSquadcastProvider() + options.PathPattern += region + "/" + err := Import(provider, options, []string{refreshToken, region, teamName, serviceName}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newSquadcastProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "user", "") + cmd.PersistentFlags().StringVarP(&refreshToken, "refresh-token", "", "", "YOUR_SQUADCAST_REFRESH_TOKEN or env variable SQUADCAST_REFRESH_TOKEN") + cmd.PersistentFlags().StringVarP(®ion, "region", "", "", "eu or us") + cmd.PersistentFlags().StringVarP(&teamName, "team-name", "", "", "Squadcast team name") + cmd.PersistentFlags().StringVarP(&serviceName, "service-name", "", "", "Squadcast service name") + return cmd +} + +func newSquadcastProvider() terraformutils.ProviderGenerator { + return &squadcast_terraforming.SCProvider{} +} diff --git a/cmd/root.go b/cmd/root.go index 3099161f0..8a16001f9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -78,6 +78,7 @@ func providerImporterSubcommands() []func(options ImportOptions) *cobra.Command newCmdPagerDutyImporter, newCmdOpsgenieImporter, newCmdHoneycombioImporter, + newCmdSquadcastImporter, newCmdOpalImporter, // Community newCmdKeycloakImporter, diff --git a/docs/squadcast.md b/docs/squadcast.md new file mode 100644 index 000000000..8ff517a47 --- /dev/null +++ b/docs/squadcast.md @@ -0,0 +1,143 @@ +# Use with Squadcast + +Syntax: + +`export SQUADCAST_REFRESH_TOKEN=` + +OR + +Add `--refresh-token` flag in cmd + +``` +terraformer import squadcast --resources= --region=SQUADCAST_REGION +``` + +### Examples: + +- `Import Resource by providing refresh-token as a flag` + +``` +terraformer import squadcast --resources=team --region=us --team-name="Default Team" --refresh-token=YOUR_REFRESH_TOKEN +``` + +- `Import User Resource` + +``` +terraformer import squadcast --resources=user --region=us --team-name="Defualt Team" +``` + +- `Import Squad Resource` + +``` +terraformer import squadcast --resources=team --region=us --team-name="Default Team" +``` + +- `Import Deduplication Rules Resource` (without `--service-name` flag) + - Deduplication Rules for all the services under Default Team will be generated. + +``` +terraformer import squadcast --resources=deduplication_rules --region=us --team-name="Default Team" +``` + +- `Import Deduplication Rules Resource` + - Deduplication Rules only for Example Service will be generated. + +``` +terraformer import squadcast --resources=deduplication_rules --region=us --team-name="Default Team" --service-name="Example Service" +``` + +### In order to use terraform files: + +- Update version and add source in `provider.tf` + - Go to `/generated/squadcast///provider.tf` + - Add `source = "SquadcastHub/squadcast"` to squadcast inside `required_providers` + - Update `version` in `required_providers` by removing `.exe` (Windows users only) +- Update `terraform_version` + - `cd /generated/squadcast//` + - `terraform state replace-provider -auto-approve "registry.terraform.io/-/squadcast" "SquadcastHub/squadcast"` + +### Example: + +``` +terraform { + required_providers { + squadcast = { + version = "~> 2.0.1" + source = "SquadcastHub/squadcast" + } + } +} +``` + +### Flags: + +- `--team-name` + + - Required for the following resources: + - deduplication_rules + - escalation_policy + - routing_rules + - runbook + - service + - slo + - squad + - suppression_rules + - tagging_rules + - team_member + - team_roles + - user + - webform + - schedules_v2 + - global_event_rules + - status_pages + - status_page_components + - status_page_groups + +- `--region` + + - Supported Values: + - `us` + - `eu` + +- `--service-name` (optional) + + - Supported for the following resources: + - deduplication_rules + - routing_rules + - suppression_rules + - tagging_rules + - deduplication_rules_v2 + - routing_rules_v2 + - suppression_rules_v2 + - tagging_rules_v2 + - If service name is not provided, resources for specified automation rule for all the service within the specified team will be generated. However it will only generate for a specific service when this flag is used. [see examples](squadcast.md:36) + +- `--refresh-token` (optional) + - Supported Values: + - + +### Supported resources: + +- [`deduplication_rules`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/deduplication_rules) +- [`deduplication_rule_v2`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/deduplication_rule_v2) +- [`escalation_policy`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/escalation_policy) +- [`routing_rules`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/routing_rules) +- [`routing_rule_v2`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/routing_rule_v2) +- [`runbook`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/runbook) +- [`service`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/service) +- [`slo`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/slo) +- [`squad`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/squad) +- [`suppression_rules`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/suppression_rules) +- [`suppression_rule_v2`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/suppression_rule_v2) +- [`tagging_rules`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/tagging_rules) +- [`tagging_rule_v2`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/tagging_rule_v2) +- [`team`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/team) +- [`team_member`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/team_member) +- [`team_roles`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/team_role) +- [`user`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/user) +- [`webforms`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/webform) +- [`status_pages`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/status_page) +- [`status_page_components`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/status_page_component) +- [`status_page_groups`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/status_page_group) +- [`global_event_rules`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/ger) +- [`schedules_v2`](https://registry.terraform.io/providers/SquadcastHub/squadcast/latest/docs/resources/schedule_v2) diff --git a/go.mod b/go.mod index ac705d93b..c0846bd07 100644 --- a/go.mod +++ b/go.mod @@ -257,7 +257,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/jsonapi v1.0.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -389,11 +389,13 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect + nhooyr.io/websocket v1.8.10 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect ) require ( github.com/gofrs/uuid/v3 v3.1.2 + github.com/hasura/go-graphql-client v0.12.1 github.com/ionos-cloud/sdk-go-cert-manager v1.0.0 github.com/ionos-cloud/sdk-go-container-registry v1.0.0 github.com/ionos-cloud/sdk-go-dataplatform v1.0.1 diff --git a/go.sum b/go.sum index 31eccc180..d4f682508 100644 --- a/go.sum +++ b/go.sum @@ -895,6 +895,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= @@ -1036,6 +1038,8 @@ github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bA github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hasura/go-graphql-client v0.12.1 h1:tL+BCoyubkYYyaQ+tJz+oPe/pSxYwOJHwe5SSqqi6WI= +github.com/hasura/go-graphql-client v0.12.1/go.mod h1:F4N4kR6vY8amio3gEu3tjSZr8GPOXJr3zj72DKixfLE= 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.4.1 h1:J1nNnR3/571b2iUDHl+y1B3VkhKm6YOXIq9GGzQUv5s= @@ -2416,6 +2420,8 @@ k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdi k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= 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= diff --git a/providers/squadcast/deduplication_rules.go b/providers/squadcast/deduplication_rules.go new file mode 100644 index 000000000..0eeb239c0 --- /dev/null +++ b/providers/squadcast/deduplication_rules.go @@ -0,0 +1,84 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type DeduplicationRulesGenerator struct { + SCService +} + +type DeduplicationRules struct { + ID string `json:"id"` + ServiceID string `json:"service_id"` + Rules []*DeduplicationRule `json:"rules"` +} + +type DeduplicationRule struct { + ID string `json:"rule_id"` +} + +func (g *DeduplicationRulesGenerator) createResources(deduplicationRules DeduplicationRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range deduplicationRules.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("deduplication_rule_%s", rule.ID), + "squadcast_deduplication_rules", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": deduplicationRules.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *DeduplicationRulesGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + req := TRequest{ + URL: "/v3/services", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/deduplication-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[DeduplicationRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/deduplication-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[DeduplicationRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/deduplocation_rules_v2.go b/providers/squadcast/deduplocation_rules_v2.go new file mode 100644 index 000000000..4e832e366 --- /dev/null +++ b/providers/squadcast/deduplocation_rules_v2.go @@ -0,0 +1,79 @@ +package squadcast + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type DeduplicationRuleGenerator struct { + SCService +} + +func (g *DeduplicationRuleGenerator) createResources(deduplicationRulesV2 DeduplicationRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range deduplicationRulesV2.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("deduplication_rule_v2_%s", rule.ID), + "squadcast_deduplication_rule_v2", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": deduplicationRulesV2.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *DeduplicationRuleGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + getServicesURL := "/v3/services" + if strings.TrimSpace(g.Args["team_id"].(string)) != "" { + getServicesURL = fmt.Sprintf("/v3/services?owner_id=%s", g.Args["team_id"].(string)) + } + req := TRequest{ + URL: getServicesURL, + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/deduplication-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[DeduplicationRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/deduplication-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[DeduplicationRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/escalation_policy.go b/providers/squadcast/escalation_policy.go new file mode 100644 index 000000000..55a62d747 --- /dev/null +++ b/providers/squadcast/escalation_policy.go @@ -0,0 +1,51 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type EscalationPolicyGenerator struct { + SCService +} + +type EscalationPolicy struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func (g *EscalationPolicyGenerator) createResources(policies []EscalationPolicy) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, policy := range policies { + resourceList = append(resourceList, terraformutils.NewResource( + policy.ID, + fmt.Sprintf("policy_%s", policy.Name), + "squadcast_escalation_policy", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *EscalationPolicyGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/escalation-policies?owner_id=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + + response, _, err := Request[[]EscalationPolicy](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/global_event_rules.go b/providers/squadcast/global_event_rules.go new file mode 100644 index 000000000..9d6c79aa0 --- /dev/null +++ b/providers/squadcast/global_event_rules.go @@ -0,0 +1,170 @@ +package squadcast + +import ( + "fmt" + "log" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type GlobalEventRulesGenerator struct { + SCService +} + +type GER struct { + ID uint `json:"id"` + Rulesets []GER_Ruleset `json:"rulesets"` +} +type GER_Ruleset struct { + ID uint `json:"id"` + AlertSourceName string + AlertSourceShortName string `json:"alert_source_shortname"` + AlertSourceVersion string `json:"alert_source_version"` + + Rules []GER_Ruleset_Rules +} +type GER_Ruleset_Rules struct { + ID uint `json:"id"` + GER_ID uint `json:"global_event_rule_id"` +} + +func (g *GlobalEventRulesGenerator) createResources(ger []GER) []terraformutils.Resource { + var resourceList []terraformutils.Resource + alertSourcesMap, err := g.getAlertSources() + if err != nil { + log.Fatal(err) + } + for _, rule := range ger { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", rule.ID), + fmt.Sprintf("ger_%d", rule.ID), + "squadcast_ger", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + for _, rs := range rule.Rulesets { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", rs.ID), + fmt.Sprintf("ger_ruleset_%d", rs.ID), + "squadcast_ger_ruleset", + g.GetProviderName(), + map[string]string{ + "ger_id": fmt.Sprintf("%d", rule.ID), + "alert_source": alertSourcesMap[rs.AlertSourceShortName], + "alert_source_shortname": rs.AlertSourceShortName, + "alert_source_version": rs.AlertSourceVersion, + }, + []string{}, + map[string]interface{}{}, + )) + + for _, r := range rs.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", r.ID), + fmt.Sprintf("ger_ruleset_rule_%d", r.ID), + "squadcast_ger_ruleset_rule", + g.GetProviderName(), + map[string]string{ + "ger_id": fmt.Sprintf("%d", rule.ID), + "alert_source": alertSourcesMap[rs.AlertSourceShortName], + "alert_source_shortname": rs.AlertSourceShortName, + "alert_source_version": rs.AlertSourceVersion, + }, + []string{}, + map[string]interface{}{}, + )) + + } + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", rs.ID), + fmt.Sprintf("ger_ruleset_rules_ordering_%d", rs.ID), + "squadcast_ger_ruleset_rules_ordering", + g.GetProviderName(), + map[string]string{ + "ger_id": fmt.Sprintf("%d", rule.ID), + "alert_source": alertSourcesMap[rs.AlertSourceShortName], + "alert_source_shortname": rs.AlertSourceShortName, + "alert_source_version": rs.AlertSourceVersion, + }, + []string{}, + map[string]interface{}{}, + )) + } + } + return resourceList +} + +func (g *GlobalEventRulesGenerator) InitResources() error { + var allRules []GER + page := 1 + pageSize := 100 + + for { + req := TRequest{ + URL: fmt.Sprintf("/v3/global-event-rules?owner_id=%s&page_number=%d&page_size=%d", g.Args["team_id"].(string), page, pageSize), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + + response, meta, err := Request[[]GER](req) + if err != nil { + return err + } + + allRules = append(allRules, *response...) + if page*pageSize >= meta.TotalCount { + break + } + + page++ + } + + for i, rule := range allRules { + for j, rs := range rule.Rulesets { + req := TRequest{ + URL: fmt.Sprintf("/v3/global-event-rules/%d/rulesets/%s/%s/rules?page_number=1&page_size=100", rule.ID, rs.AlertSourceVersion, rs.AlertSourceShortName), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + resp, _, err := Request[[]GER_Ruleset_Rules](req) + if err != nil { + return err + } + allRules[i].Rulesets[j].Rules = *resp + } + } + + g.Resources = g.createResources(allRules) + return nil +} + +type AlertSource struct { + Type string `json:"type"` + ShortName string `json:"shortName"` + Version string `json:"version"` +} + +func (g *GlobalEventRulesGenerator) getAlertSources() (map[string]string, error) { + alertSourcesMap := make(map[string]string, 0) + req := TRequest{ + URL: "/v2/public/integrations", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + IsV2: true, + } + alertSources, _, err := Request[[]AlertSource](req) + if err != nil { + return nil, err + } + for _, alertSourceData := range *alertSources { + alertSourcesMap[alertSourceData.ShortName] = alertSourceData.Type + } + return alertSourcesMap, nil +} diff --git a/providers/squadcast/routing_rules.go b/providers/squadcast/routing_rules.go new file mode 100644 index 000000000..8ac4f6dd1 --- /dev/null +++ b/providers/squadcast/routing_rules.go @@ -0,0 +1,84 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type RoutingRulesGenerator struct { + SCService +} + +type RoutingRules struct { + ID string `json:"id"` + ServiceID string `json:"service_id"` + Rules []*RoutingRule `json:"rules"` +} + +type RoutingRule struct { + ID string `json:"rule_id"` +} + +func (g *RoutingRulesGenerator) createResources(routingRules RoutingRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range routingRules.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("routing_rule_%s", rule.ID), + "squadcast_routing_rules", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": routingRules.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *RoutingRulesGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + req := TRequest{ + URL: "/v3/services", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/routing-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[RoutingRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/routing-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[RoutingRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/routing_rules_v2.go b/providers/squadcast/routing_rules_v2.go new file mode 100644 index 000000000..74989af27 --- /dev/null +++ b/providers/squadcast/routing_rules_v2.go @@ -0,0 +1,79 @@ +package squadcast + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type RoutingRuleGenerator struct { + SCService +} + +func (g *RoutingRuleGenerator) createResources(routingRules RoutingRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range routingRules.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("routing_rule_v2_%s", rule.ID), + "squadcast_routing_rule_v2", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": routingRules.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *RoutingRuleGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + getServicesURL := "/v3/services" + if strings.TrimSpace(g.Args["team_id"].(string)) != "" { + getServicesURL = fmt.Sprintf("/v3/services?owner_id=%s", g.Args["team_id"].(string)) + } + req := TRequest{ + URL: getServicesURL, + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/routing-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[RoutingRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/routing-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[RoutingRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/runbook.go b/providers/squadcast/runbook.go new file mode 100644 index 000000000..ab68d9eb1 --- /dev/null +++ b/providers/squadcast/runbook.go @@ -0,0 +1,52 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type RunbookGenerator struct { + SCService +} + +type Runbook struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func (g *RunbookGenerator) createResources(runbooks []Runbook) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, runbook := range runbooks { + resourceList = append(resourceList, terraformutils.NewResource( + runbook.ID, + fmt.Sprintf("runbook_%s", runbook.Name), + "squadcast_runbook", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *RunbookGenerator) InitResources() error { + req := TRequest{ + URL: "/v3/runbooks", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]Runbook](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/schedules_v2.go b/providers/squadcast/schedules_v2.go new file mode 100644 index 000000000..e474d0696 --- /dev/null +++ b/providers/squadcast/schedules_v2.go @@ -0,0 +1,75 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SchedulesGenerator struct { + SCService +} + +type ScheduleQueryStruct struct { + Schedules []*Schedule `graphql:"schedules(filters: { teamID: $teamID })"` +} + +type Schedule struct { + ID int `graphql:"ID" json:"ID"` + Rotations []*Rotation `graphql:"rotations" json:"rotations"` +} + +type Rotation struct { + ID int `graphql:"ID" json:"id"` +} + +func (g *SchedulesGenerator) createResources(schedules []*Schedule) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, sch := range schedules { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", sch.ID), + fmt.Sprintf("schedule_v2_%d", sch.ID), + "squadcast_schedule_v2", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + + for _, rot := range sch.Rotations { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", rot.ID), + fmt.Sprintf("rotation_v2_%d", rot.ID), + "squadcast_schedule_rotation_v2", + g.GetProviderName(), + map[string]string{ + "schedule_id": fmt.Sprintf("%d", sch.ID), + }, + []string{}, + map[string]interface{}{}, + )) + } + } + + return resourceList +} + +func (g *SchedulesGenerator) InitResources() error { + var payload ScheduleQueryStruct + + variables := map[string]interface{}{ + "teamID": g.Args["team_id"].(string), + } + + response, err := GraphQLRequest[ScheduleQueryStruct]("query", g.Args["access_token"].(string), g.Args["region"].(string), &payload, variables) + if err != nil { + return err + } + + g.Resources = g.createResources(response.Schedules) + return nil +} diff --git a/providers/squadcast/service.go b/providers/squadcast/service.go new file mode 100644 index 000000000..de5cbdfb4 --- /dev/null +++ b/providers/squadcast/service.go @@ -0,0 +1,57 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type ServiceGenerator struct { + SCService +} + +type Service struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func (g *ServiceGenerator) createResources(services []Service) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, service := range services { + resourceList = append(resourceList, terraformutils.NewResource( + service.ID, + fmt.Sprintf("service_%s", service.Name), + "squadcast_service", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *ServiceGenerator) InitResources() error { + getServicesURL := "/v3/services" + if strings.TrimSpace(g.Args["team_id"].(string)) != "" { + getServicesURL = fmt.Sprintf("/v3/services?owner_id=%s", g.Args["team_id"].(string)) + } + req := TRequest{ + URL: getServicesURL, + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]Service](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/slo.go b/providers/squadcast/slo.go new file mode 100644 index 000000000..c67b6a578 --- /dev/null +++ b/providers/squadcast/slo.go @@ -0,0 +1,56 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SLOGenerator struct { + SCService +} + +type SLO struct { + ID int `json:"id"` + Name string `json:"name"` +} + +type getSLOsResponse struct { + SLOs *[]SLO `json:"slos"` +} + +func (g *SLOGenerator) createResources(slo []SLO) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, s := range slo { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", s.ID), + fmt.Sprintf("slo_%s", s.Name), + "squadcast_slo", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *SLOGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/slo?owner_id=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[getSLOsResponse](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response.SLOs) + return nil +} diff --git a/providers/squadcast/squad.go b/providers/squadcast/squad.go new file mode 100644 index 000000000..6cdf5059e --- /dev/null +++ b/providers/squadcast/squad.go @@ -0,0 +1,51 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SquadGenerator struct { + SCService +} + +type Squad struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func (g *SquadGenerator) createResources(squads []Squad) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, squad := range squads { + resourceList = append(resourceList, terraformutils.NewResource( + squad.ID, + fmt.Sprintf("squad_%s", squad.Name), + "squadcast_squad", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "name": squad.Name, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *SquadGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/squads?owner_id=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]Squad](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/squadcast_provider.go b/providers/squadcast/squadcast_provider.go new file mode 100644 index 000000000..a6e27d8d2 --- /dev/null +++ b/providers/squadcast/squadcast_provider.go @@ -0,0 +1,192 @@ +package squadcast + +import ( + "errors" + "fmt" + "log" + "net/url" + "os" + + "github.com/zclconf/go-cty/cty" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SCProvider struct { + terraformutils.Provider + accessToken string + refreshToken string + region string + teamID string + teamName string + serviceName string + serviceID string +} + +type AccessToken struct { + AccessToken string `json:"access_token"` +} + +// Meta holds the status of the request information +type Meta struct { + Meta AppError `json:"meta,omitempty"` + TotalCount int `json:"total_count"` + TotalPages int `json:"totalCount"` +} + +type AppError struct { + Status int `json:"status"` + Message string `json:"error_message,omitempty"` +} + +func (p *SCProvider) Init(args []string) error { + if refreshToken := os.Getenv("SQUADCAST_REFRESH_TOKEN"); refreshToken != "" { + p.refreshToken = os.Getenv("SQUADCAST_REFRESH_TOKEN") + } + if args[0] != "" { + p.refreshToken = args[0] + } + if p.refreshToken == "" { + return errors.New("required refresh Token missing") + } + + if region := os.Getenv("SQUADCAST_REGION"); region != "" { + p.region = os.Getenv("SQUADCAST_REGION") + } + if args[1] == "" { + return errors.New("required region missing") + } + p.region = args[1] + p.GetAccessToken() + + if args[2] == "" { + return errors.New("required team name missing") + } + p.teamName = args[2] + p.GetTeamID() + + if args[3] != "" { + p.serviceName = args[3] + p.GetServiceID() + } + + return nil +} + +func (p *SCProvider) 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()) + // SetArgs are used for fetching details within other files in the terraformer code. + p.Service.SetArgs(map[string]interface{}{ + "access_token": p.accessToken, + "region": p.region, + "team_id": p.teamID, + "team_name": p.teamName, + "service_name": p.serviceName, + "service_id": p.serviceID, + }) + return nil +} + +// @desc GetConfig: send details to provider block of terraform-provider-squadcast + +func (p *SCProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "region": cty.StringVal(p.region), + "refresh_token": cty.StringVal(p.refreshToken), + }) +} + +func (p *SCProvider) GetProviderData(...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "squadcast": map[string]interface{}{ + "region": p.region, + }, + }, + } +} + +func (p *SCProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} + +func (p *SCProvider) GetName() string { + return "squadcast" +} + +func (p *SCProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "user": &UserGenerator{}, + "service": &ServiceGenerator{}, + "squad": &SquadGenerator{}, + "team": &TeamGenerator{}, + "team_member": &TeamMemberGenerator{}, + "team_roles": &TeamRolesGenerator{}, + "escalation_policy": &EscalationPolicyGenerator{}, + "runbook": &RunbookGenerator{}, + "slo": &SLOGenerator{}, + "tagging_rules": &TaggingRulesGenerator{}, + "tagging_rule_v2": &TaggingRuleGenerator{}, + "routing_rules": &RoutingRulesGenerator{}, + "routing_rule_v2": &RoutingRuleGenerator{}, + "deduplication_rules": &DeduplicationRulesGenerator{}, + "deduplication_rule_v2": &DeduplicationRuleGenerator{}, + "suppression_rules": &SuppressionRulesGenerator{}, + "suppression_rule_v2": &SuppressionRuleGenerator{}, + "global_event_rules": &GlobalEventRulesGenerator{}, + "webforms": &WebformsGenerator{}, + "status_pages": &StatusPagesGenerator{}, + "status_page_components": &StatusPageComponentsGenerator{}, + "status_page_groups": &StatusPageGroupsGenerator{}, + "schedules_v2": &SchedulesGenerator{}, + } +} + +func (p *SCProvider) GetAccessToken() { + req := TRequest{ + URL: "/oauth/access-token", + RefreshToken: p.refreshToken, + Region: p.region, + IsAuthenticated: false, + } + response, _, err := Request[AccessToken](req) + if err != nil { + log.Fatal(err) + } + p.accessToken = response.AccessToken +} + +func (p *SCProvider) GetTeamID() { + req := TRequest{ + URL: fmt.Sprintf("/v3/teams/by-name?name=%s", url.QueryEscape(p.teamName)), + AccessToken: p.accessToken, + Region: p.region, + IsAuthenticated: true, + } + response, _, err := Request[Team](req) + if err != nil { + log.Fatal(err) + } + p.teamID = response.ID +} + +func (p *SCProvider) GetServiceID() { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/by-name?name=%s&owner_id=%s", url.QueryEscape(p.serviceName), p.teamID), + AccessToken: p.accessToken, + Region: p.region, + IsAuthenticated: true, + } + response, _, err := Request[Service](req) + if err != nil { + log.Fatal(err) + } + p.serviceID = response.ID +} diff --git a/providers/squadcast/squadcast_service.go b/providers/squadcast/squadcast_service.go new file mode 100644 index 000000000..2fef0e30b --- /dev/null +++ b/providers/squadcast/squadcast_service.go @@ -0,0 +1,123 @@ +package squadcast + +import ( + "context" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + + "github.com/hasura/go-graphql-client" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SCService struct { + terraformutils.Service +} + +const ( + UserAgent = "terraformer-squadcast" +) + +func getHost(region string) string { + switch region { + case "us": + return "squadcast.com" + case "eu": + return "eu.squadcast.com" + case "staging": + return "squadcast.tech" + default: + return "" + } +} + +type TRequest struct { + URL string + AccessToken string + RefreshToken string + Region string + IsAuthenticated bool + IsV2 bool +} + +func Request[TRes any](request TRequest) (*TRes, *Meta, error) { + ctx := context.Background() + var URL string + var req *http.Request + var err error + host := getHost(request.Region) + if request.IsAuthenticated { + if !request.IsV2 { + URL = fmt.Sprintf("https://api.%s%s", host, request.URL) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, URL, nil) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", request.AccessToken)) + } else { + URL = fmt.Sprintf("https://platform-backend.%s%s", host, request.URL) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, URL, nil) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", request.AccessToken)) + } + } else { + URL = fmt.Sprintf("https://auth.%s%s", host, request.URL) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, URL, nil) + req.Header.Set("X-Refresh-Token", request.RefreshToken) + } + if err != nil { + return nil, nil, err + } + + req.Header.Set("User-Agent", UserAgent) + resp, err := http.DefaultClient.Do(req) + + var response struct { + Data *TRes `json:"data"` + Meta *Meta `json:"meta"` + } + if err != nil { + return nil, nil, err + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + log.Fatal(err) + } + }(resp.Body) + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, nil, err + } + + err = json.Unmarshal(body, &response) + if err != nil { + return nil, nil, err + } + if response.Meta != nil { + if response.Meta.Meta.Status >= 400 { + return nil, nil, fmt.Errorf("error: %s", response.Meta.Meta.Message) + } + } + + return response.Data, response.Meta, nil +} + +var gqlClient *graphql.Client + +func GraphQLRequest[TReq any](method string, token string, region string, payload *TReq, variables map[string]interface{}) (*TReq, error) { + graphQLURL := fmt.Sprintf("https://api.%s/v3/graphql", getHost(region)) + bearerToken := fmt.Sprintf("Bearer %s", token) + + if gqlClient == nil { + gqlClient = graphql.NewClient(graphQLURL, nil).WithRequestModifier(func(req *http.Request) { + req.Header.Set("Authorization", bearerToken) + }) + } + if err := gqlClient.WithDebug(false).Query(context.Background(), payload, variables); err != nil { + return nil, err + } + + return payload, nil +} diff --git a/providers/squadcast/status_page.go b/providers/squadcast/status_page.go new file mode 100644 index 000000000..543c06e74 --- /dev/null +++ b/providers/squadcast/status_page.go @@ -0,0 +1,61 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type StatusPagesGenerator struct { + SCService +} + +type StatusPage struct { + ID uint `json:"id"` +} + +func (g *StatusPagesGenerator) createResources(statusPages []StatusPage) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, sp := range statusPages { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", sp.ID), + fmt.Sprintf("status_page_%d", sp.ID), + "squadcast_status_page", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *StatusPagesGenerator) InitResources() error { + var allStatusPages []StatusPage + page := 1 + pageSize := 100 + for { + req := TRequest{ + URL: fmt.Sprintf("/v4/statuspages?teamID=%s&pageNumber=%d&pageSize=%d", g.Args["team_id"].(string), page, pageSize), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, meta, err := Request[[]StatusPage](req) + if err != nil { + return err + } + allStatusPages = append(allStatusPages, *response...) + if page*pageSize >= meta.TotalPages { + break + } + page++ + } + + g.Resources = g.createResources(allStatusPages) + return nil +} diff --git a/providers/squadcast/status_page_components.go b/providers/squadcast/status_page_components.go new file mode 100644 index 000000000..b8b2d2457 --- /dev/null +++ b/providers/squadcast/status_page_components.go @@ -0,0 +1,64 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type StatusPageComponentsGenerator struct { + SCService +} + +type StatusPageComponent struct { + ID uint `json:"id"` + PageID uint `json:"pageID"` +} + +func (g *StatusPageComponentsGenerator) createResources(statusPageComponents []StatusPageComponent) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, spc := range statusPageComponents { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", spc.ID), + fmt.Sprintf("status_page_component_%d", spc.ID), + "squadcast_status_page_component", + g.GetProviderName(), + map[string]string{ + "status_page_id": fmt.Sprintf("%d", spc.PageID), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *StatusPageComponentsGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v4/statuspages?teamID=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]StatusPage](req) + if err != nil { + return err + } + for _, sp := range *response { + req := TRequest{ + URL: fmt.Sprintf("/v4/statuspages/%d/components", sp.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]StatusPageComponent](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + return nil +} diff --git a/providers/squadcast/status_page_groups.go b/providers/squadcast/status_page_groups.go new file mode 100644 index 000000000..d35fa1bcb --- /dev/null +++ b/providers/squadcast/status_page_groups.go @@ -0,0 +1,64 @@ +// service resource is yet to be implemented + +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type StatusPageGroupsGenerator struct { + SCService +} + +type StatusPageGroup struct { + ID uint `json:"id"` + PageID uint `json:"pageID"` +} + +func (g *StatusPageGroupsGenerator) createResources(statusPageGroups []StatusPageGroup) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, spc := range statusPageGroups { + resourceList = append(resourceList, terraformutils.NewResource( + fmt.Sprintf("%d", spc.ID), + fmt.Sprintf("status_page_group_%d", spc.ID), + "squadcast_status_page_group", + g.GetProviderName(), + map[string]string{ + "status_page_id": fmt.Sprintf("%d", spc.PageID), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *StatusPageGroupsGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v4/statuspages?teamID=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]StatusPage](req) + if err != nil { + return err + } + for _, sp := range *response { + req := TRequest{ + URL: fmt.Sprintf("/v4/statuspages/%d/groups", sp.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]StatusPageGroup](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + return nil +} diff --git a/providers/squadcast/suppression_rule_v2.go b/providers/squadcast/suppression_rule_v2.go new file mode 100644 index 000000000..59519150d --- /dev/null +++ b/providers/squadcast/suppression_rule_v2.go @@ -0,0 +1,79 @@ +package squadcast + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SuppressionRuleGenerator struct { + SCService +} + +func (g *SuppressionRuleGenerator) createResources(suppressionRules SuppressionRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range suppressionRules.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("suppression_rule_v2_%s", rule.ID), + "squadcast_suppression_rule_v2", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": suppressionRules.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *SuppressionRuleGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + getServicesURL := "/v3/services" + if strings.TrimSpace(g.Args["team_id"].(string)) != "" { + getServicesURL = fmt.Sprintf("/v3/services?owner_id=%s", g.Args["team_id"].(string)) + } + req := TRequest{ + URL: getServicesURL, + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/suppression-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[SuppressionRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/suppression-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[SuppressionRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/suppression_rules.go b/providers/squadcast/suppression_rules.go new file mode 100644 index 000000000..ea3021e15 --- /dev/null +++ b/providers/squadcast/suppression_rules.go @@ -0,0 +1,84 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type SuppressionRulesGenerator struct { + SCService +} + +type SuppressionRules struct { + ID string `json:"id"` + ServiceID string `json:"service_id"` + Rules []*SuppressionRule `json:"rules"` +} + +type SuppressionRule struct { + ID string `json:"rule_id"` +} + +func (g *SuppressionRulesGenerator) createResources(suppressionRules SuppressionRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range suppressionRules.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("suppression_rule_%s", rule.ID), + "squadcast_suppression_rules", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": suppressionRules.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *SuppressionRulesGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + req := TRequest{ + URL: "/v3/services", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/suppression-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[SuppressionRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/suppression-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[SuppressionRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/tagging_rule_v2.go b/providers/squadcast/tagging_rule_v2.go new file mode 100644 index 000000000..c653927b7 --- /dev/null +++ b/providers/squadcast/tagging_rule_v2.go @@ -0,0 +1,79 @@ +package squadcast + +import ( + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TaggingRuleGenerator struct { + SCService +} + +func (g *TaggingRuleGenerator) createResources(taggingRule TaggingRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range taggingRule.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("tagging_rule_v2_%s", rule.ID), + "squadcast_tagging_rule_v2", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": taggingRule.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *TaggingRuleGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + getServicesURL := "/v3/services" + if strings.TrimSpace(g.Args["team_id"].(string)) != "" { + getServicesURL = fmt.Sprintf("/v3/services?owner_id=%s", g.Args["team_id"].(string)) + } + req := TRequest{ + URL: getServicesURL, + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/tagging-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[TaggingRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/tagging-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[TaggingRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/tagging_rules.go b/providers/squadcast/tagging_rules.go new file mode 100644 index 000000000..9413d2442 --- /dev/null +++ b/providers/squadcast/tagging_rules.go @@ -0,0 +1,84 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TaggingRulesGenerator struct { + SCService +} + +type TaggingRules struct { + ID string `json:"id"` + ServiceID string `json:"service_id"` + Rules []*TaggingRule `json:"rules"` +} + +type TaggingRule struct { + ID string `json:"rule_id"` +} + +func (g *TaggingRulesGenerator) createResources(taggingRule TaggingRules) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, rule := range taggingRule.Rules { + resourceList = append(resourceList, terraformutils.NewResource( + rule.ID, + fmt.Sprintf("tagging_rule_%s", rule.ID), + "squadcast_tagging_rules", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + "service_id": taggingRule.ServiceID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *TaggingRulesGenerator) InitResources() error { + if len(g.Args["service_name"].(string)) == 0 { + req := TRequest{ + URL: "/v3/services", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + responseService, _, err := Request[[]Service](req) + if err != nil { + return err + } + + for _, service := range *responseService { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/tagging-rules", service.ID), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[TaggingRules](req) + if err != nil { + return err + } + + g.Resources = append(g.Resources, g.createResources(*response)...) + } + } else { + req := TRequest{ + URL: fmt.Sprintf("/v3/services/%s/tagging-rules", g.Args["service_id"]), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[TaggingRules](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + } + return nil +} diff --git a/providers/squadcast/team.go b/providers/squadcast/team.go new file mode 100644 index 000000000..ceb8f349a --- /dev/null +++ b/providers/squadcast/team.go @@ -0,0 +1,48 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TeamGenerator struct { + SCService +} + +type Team struct { + ID string `json:"id"` + Name string `json:"name"` + Members []*TeamMember `json:"members"` + Roles []*TeamRole `json:"roles"` +} + +func (g *TeamGenerator) createResources(teams []Team) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, team := range teams { + resourceList = append(resourceList, terraformutils.NewSimpleResource( + team.ID, + fmt.Sprintf("team_%s", team.Name), + "squadcast_team", + g.GetProviderName(), + []string{}, + )) + } + return resourceList +} + +func (g *TeamGenerator) InitResources() error { + req := TRequest{ + URL: "/v3/teams", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]Team](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/team_member.go b/providers/squadcast/team_member.go new file mode 100644 index 000000000..a26ef4ba0 --- /dev/null +++ b/providers/squadcast/team_member.go @@ -0,0 +1,51 @@ +package squadcast + +import ( + "fmt" + "net/url" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TeamMemberGenerator struct { + SCService +} + +type TeamMember struct { + UserID string `json:"user_id"` +} + +func (g *TeamMemberGenerator) createResources(team Team) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, member := range team.Members { + resourceList = append(resourceList, terraformutils.NewResource( + member.UserID, + fmt.Sprintf("squadcast_team_member_%s", member.UserID), + "squadcast_team_member", + g.GetProviderName(), + map[string]string{ + "team_id": team.ID, + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *TeamMemberGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/teams/by-name?name=%s", url.QueryEscape(g.Args["team_name"].(string))), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + + response, _, err := Request[Team](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/team_roles.go b/providers/squadcast/team_roles.go new file mode 100644 index 000000000..1660bef65 --- /dev/null +++ b/providers/squadcast/team_roles.go @@ -0,0 +1,50 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type TeamRolesGenerator struct { + SCService +} + +type TeamRole struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func (g *TeamRolesGenerator) createResources(teamRoles []TeamRole) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, role := range teamRoles { + resourceList = append(resourceList, terraformutils.NewResource( + role.ID, + fmt.Sprintf("team_role_%s", role.Name), + "squadcast_team_role", + g.GetProviderName(), + map[string]string{ + "team_id": g.Args["team_id"].(string), + }, + []string{}, + map[string]interface{}{}, + )) + } + return resourceList +} + +func (g *TeamRolesGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/teams/%s/roles", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]TeamRole](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/user.go b/providers/squadcast/user.go new file mode 100644 index 000000000..f6e337ab1 --- /dev/null +++ b/providers/squadcast/user.go @@ -0,0 +1,45 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type UserGenerator struct { + SCService +} + +type User struct { + ID string `json:"id"` +} + +func (g *UserGenerator) createResources(users []User) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, user := range users { + resourceList = append(resourceList, terraformutils.NewSimpleResource( + user.ID, + fmt.Sprintf("user_%s", user.ID), + "squadcast_user", + g.GetProviderName(), + []string{}, + )) + } + return resourceList +} + +func (g *UserGenerator) InitResources() error { + req := TRequest{ + URL: "/v3/users", + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]User](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +} diff --git a/providers/squadcast/webform.go b/providers/squadcast/webform.go new file mode 100644 index 000000000..9f5ba7449 --- /dev/null +++ b/providers/squadcast/webform.go @@ -0,0 +1,45 @@ +package squadcast + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" +) + +type WebformsGenerator struct { + SCService +} + +type Webform struct { + ID uint `json:"id"` +} + +func (g *WebformsGenerator) createResources(webforms []Webform) []terraformutils.Resource { + var resourceList []terraformutils.Resource + for _, webform := range webforms { + resourceList = append(resourceList, terraformutils.NewSimpleResource( + fmt.Sprintf("%d", webform.ID), + fmt.Sprintf("webform_%d", webform.ID), + "squadcast_webform", + g.GetProviderName(), + []string{}, + )) + } + return resourceList +} + +func (g *WebformsGenerator) InitResources() error { + req := TRequest{ + URL: fmt.Sprintf("/v3/webforms?owner_id=%s", g.Args["team_id"].(string)), + AccessToken: g.Args["access_token"].(string), + Region: g.Args["region"].(string), + IsAuthenticated: true, + } + response, _, err := Request[[]Webform](req) + if err != nil { + return err + } + + g.Resources = g.createResources(*response) + return nil +}