From 789423f2a3beb089a8615b3498134506375280dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tommy=20M=C3=BChle?= Date: Tue, 9 Nov 2021 06:42:36 +0100 Subject: [PATCH] Add "Opsgenie" as further provider (#1124) --- README.md | 2 + cmd/provider_cmd_opsgenie.go | 33 ++++++++++++ cmd/root.go | 1 + docs/opsgenie.md | 14 +++++ go.mod | 1 + go.sum | 3 ++ providers/opsgenie/opsgenie_provider.go | 70 +++++++++++++++++++++++++ providers/opsgenie/opsgenie_service.go | 21 ++++++++ providers/opsgenie/team.go | 50 ++++++++++++++++++ providers/opsgenie/user.go | 68 ++++++++++++++++++++++++ 10 files changed, 263 insertions(+) create mode 100644 cmd/provider_cmd_opsgenie.go create mode 100644 docs/opsgenie.md create mode 100644 providers/opsgenie/opsgenie_provider.go create mode 100644 providers/opsgenie/opsgenie_service.go create mode 100644 providers/opsgenie/team.go create mode 100644 providers/opsgenie/user.go diff --git a/README.md b/README.md index 32d4c7016..28a643e1d 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ A CLI tool that generates `tf`/`json` and `tfstate` files based on existing infr * [Datadog](/docs/datadog.md) * [New Relic](/docs/relic.md) * [PagerDuty](/docs/pagerduty.md) + * [Opsgenie](/docs/opsgenie.md) * Community * [Keycloak](/docs/keycloak.md) * [Logz.io](/docs/logz.md) @@ -277,6 +278,7 @@ Links to download Terraform Providers: * 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/) * 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/) 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/root.go b/cmd/root.go index 730ae1689..d5617731a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -71,6 +71,7 @@ func providerImporterSubcommands() []func(options ImportOptions) *cobra.Command newCmdNewRelicImporter, newCmdGrafanaImporter, newCmdPagerDutyImporter, + newCmdOpsgenieImporter, // Community newCmdKeycloakImporter, newCmdLogzioImporter, 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/go.mod b/go.mod index 782312d60..2494d6ccc 100644 --- a/go.mod +++ b/go.mod @@ -283,6 +283,7 @@ require ( 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/opsgenie/opsgenie-go-sdk-v2 v1.2.8 // 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 diff --git a/go.sum b/go.sum index 68b0da0f9..a02145d7b 100644 --- a/go.sum +++ b/go.sum @@ -745,6 +745,7 @@ github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn 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.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -1041,6 +1042,8 @@ github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2T 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= 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 +}