diff --git a/cmd/provider_cmd_sumologic.go b/cmd/provider_cmd_sumologic.go new file mode 100644 index 000000000..dd5db72e4 --- /dev/null +++ b/cmd/provider_cmd_sumologic.go @@ -0,0 +1,47 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + sumologic_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/sumologic" + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/spf13/cobra" +) + +func newCmdSumoLogicImporter(options ImportOptions) *cobra.Command { + var accessId, accessKey, environment string + cmd := &cobra.Command{ + Use: "sumologic", + Short: "Import current state to Terraform configuration from Sumo Logic", + Long: "Import current state to Terraform configuration from Sumo Logic", + RunE: func(cmd *cobra.Command, args []string) error { + provider := newSumoLogicProvider() + err := Import(provider, options, []string{accessId, accessKey, environment}) + if err != nil { + return err + } + return nil + }, + } + cmd.AddCommand(listCmd(newSumoLogicProvider())) + baseProviderFlags(cmd.PersistentFlags(), &options, "users", "users=id1:id2:id4") + cmd.PersistentFlags().StringVarP(&accessId, "access-id", "", "", "Sumo Logic Access ID or env param SUMOLOGIC_ACCESS_ID") + cmd.PersistentFlags().StringVarP(&accessKey, "access-key", "", "", "Sumo Logic Access Key or env param SUMOLOGIC_ACCESS_KEY") + cmd.PersistentFlags().StringVarP(&environment, "environment", "", "", "Sumo Logic environment or env param SUMOLOGIC_ENVIRONMENT") + return cmd +} + +func newSumoLogicProvider() terraformutils.ProviderGenerator { + return &sumologic_terraforming.SumoLogicProvider{} +} diff --git a/cmd/root.go b/cmd/root.go index 3099161f0..eb3b9b2b8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -79,6 +79,7 @@ func providerImporterSubcommands() []func(options ImportOptions) *cobra.Command newCmdOpsgenieImporter, newCmdHoneycombioImporter, newCmdOpalImporter, + newCmdSumoLogicImporter, // Community newCmdKeycloakImporter, newCmdLogzioImporter, @@ -130,6 +131,7 @@ func providerGenerators() map[string]func() terraformutils.ProviderGenerator { newPagerDutyProvider, newHoneycombioProvider, newOpalProvider, + newSumoLogicProvider, // Community newKeycloakProvider, newLogzioProvider, diff --git a/docs/sumologic.md b/docs/sumologic.md new file mode 100644 index 000000000..3ccfbcdba --- /dev/null +++ b/docs/sumologic.md @@ -0,0 +1,43 @@ +## Use with Sumologic + +Example: + +``` +./terraformer import sumologic --resources=user --access-id=SUMOLOGIC_ACCESS_ID --access-key=SUMOLOGIC_ACCESS_KEY --environment=SUMOLOGIC_ENVIRONMENT +``` + +You can also export env vars instead of providing them via args. +``` +export SUMOLOGIC_ENVIRONMENT="us2" +export SUMOLOGIC_ACCESS_ID="US2_ACCESS_ID" +export SUMOLOGIC_ACCESS_KEY="US2_ACCESS_KEY" + +./terraformer import sumologic --resources=user +``` + +List of supported Sumologic services: + +* `connection` + * `sumologic_connection` +* `dashboard` + * `sumologic_dashboard` +* `field_extraction_rule` + * `sumologic_field_extraction_rule` +* `monitor` + * `sumologic_monitor` +* `partition` + * `sumologic_partition` +* `role` + * `sumologic_role` + + _Roles can be imported by name, which can be passed via `--filter` option._ + ``` + terraformer import sumologic --resources=role --filter 'Name=name;Value=App Admin' + ``` +* `user` + * `sumologic_user` + + _Users can be imported by email, which can be passed via `--filter` option._ + ``` + terraformer import sumologic --resources=user --filter 'Name=email;Value=johndoe@sumologic.com' + ``` diff --git a/go.mod b/go.mod index ac705d93b..4eba891f9 100644 --- a/go.mod +++ b/go.mod @@ -360,6 +360,8 @@ require ( github.com/manicminer/hamilton v0.44.0 github.com/opalsecurity/opal-go v1.0.19 gopkg.in/ns1/ns1-go.v2 v2.6.5 + github.com/sumovishal/sumologic-go-sdk v0.0.0-20220807145511-cf1ced70723b + github.com/sumovishal/sumologic-go-sdk v0.0.0-20230810134622-c151e5f7d9f6 ) require ( diff --git a/go.sum b/go.sum index 31eccc180..6e4c26fe0 100644 --- a/go.sum +++ b/go.sum @@ -1416,6 +1416,12 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20220806134908-7d671aa8dc0f h1:AQkmKYt+ffgcsd/n1GfJ4DWq1AtYXh5KNC8OGhV7iWI= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20220806134908-7d671aa8dc0f/go.mod h1:DG0EwAJA796aYF/O79yUQ5rlp5loiPU1Sf/TRXOpCmM= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20220807145511-cf1ced70723b h1:+msQGas9ER8bzezyR+hLAhdKgMURIsVd9lLs30A+cI8= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20220807145511-cf1ced70723b/go.mod h1:yqBp0ZPIjBtPjYPuxg/84peHkSFfRwEYqhZu27+xmxc= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20230810134622-c151e5f7d9f6 h1:JRqRDIVZRWiSPen/5SghdPOedtplPdBjoKMJ5xtnoKg= +github.com/sumovishal/sumologic-go-sdk v0.0.0-20230810134622-c151e5f7d9f6/go.mod h1:DG0EwAJA796aYF/O79yUQ5rlp5loiPU1Sf/TRXOpCmM= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= github.com/tencentcloud/tencentcloud-sdk-go v1.0.392/go.mod h1:l8PU0g9KTDkwn6R4F9WbXXSUwRgKs6k7rj52H4uAcM0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/aa v1.0.392/go.mod h1:DTrc+dJQjeL+2b7KEkfW1RiZqssiHxIMjRWhnt6PmU4= diff --git a/providers/sumologic/connection.go b/providers/sumologic/connection.go new file mode 100644 index 000000000..ff805882b --- /dev/null +++ b/providers/sumologic/connection.go @@ -0,0 +1,68 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type ConnectionGenerator struct { + SumoLogicService +} + +func (g *ConnectionGenerator) createResources(connections []sumologic.Connection) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(connections)) + + for i, connection := range connections { + name := strcase.ToSnake(replaceSpaceAndDash(connection.Name)) + resource := terraformutils.NewSimpleResource( + connection.Id, + fmt.Sprintf("%s-%s", name, connection.Id), + "sumologic_connection", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *ConnectionGenerator) InitResources() error { + client := g.Client() + req := client.ConnectionManagementApi.ListConnections(g.AuthCtx()) + req = req.Limit(100) + + respBody, _, err := client.ConnectionManagementApi.ListConnectionsExecute(req) + if err != nil { + return err + } + connections := respBody.Data + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.ConnectionManagementApi.ListConnectionsExecute(req) + if err != nil { + return err + } + connections = append(connections, respBody.Data...) + } + + resources := g.createResources(connections) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/dashboard.go b/providers/sumologic/dashboard.go new file mode 100644 index 000000000..2b06d4c97 --- /dev/null +++ b/providers/sumologic/dashboard.go @@ -0,0 +1,73 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type DashboardGenerator struct { + SumoLogicService +} + +func (g *DashboardGenerator) createResources(dashboards []sumologic.Dashboard) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(dashboards)) + + for i, dashboard := range dashboards { + title := strcase.ToSnake(replaceSpaceAndDash(dashboard.Title)) + + resource := terraformutils.NewSimpleResource( + *dashboard.Id, + fmt.Sprintf("%s-%s", title, *dashboard.Id), + "sumologic_dashboard", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *DashboardGenerator) InitResources() error { + client := g.Client() + + var resources []terraformutils.Resource + var dashboards []sumologic.Dashboard + + req := client.DashboardManagementApi.ListDashboards(g.AuthCtx()) + req = req.Limit(100) + + respBody, _, err := client.DashboardManagementApi.ListDashboardsExecute(req) + if err != nil { + return err + } + dashboards = respBody.Dashboards + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.DashboardManagementApi.ListDashboardsExecute(req) + if err != nil { + return err + } + dashboards = append(dashboards, respBody.Dashboards...) + } + + resources = g.createResources(dashboards) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/field_extraction_rule.go b/providers/sumologic/field_extraction_rule.go new file mode 100644 index 000000000..64c12a16b --- /dev/null +++ b/providers/sumologic/field_extraction_rule.go @@ -0,0 +1,68 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type FieldExtractionRuleGenerator struct { + SumoLogicService +} + +func (g *FieldExtractionRuleGenerator) createResources(rules []sumologic.ExtractionRule) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(rules)) + + for i, rule := range rules { + name := strcase.ToSnake(replaceSpaceAndDash(rule.Name)) + resource := terraformutils.NewSimpleResource( + rule.Id, + fmt.Sprintf("%s-%s", name, rule.Id), + "sumologic_field_extraction_rule", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *FieldExtractionRuleGenerator) InitResources() error { + client := g.Client() + req := client.ExtractionRuleManagementApi.ListExtractionRules(g.AuthCtx()) + req = req.Limit(100) + + respBody, _, err := client.ExtractionRuleManagementApi.ListExtractionRulesExecute(req) + if err != nil { + return err + } + rules := respBody.Data + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.ExtractionRuleManagementApi.ListExtractionRulesExecute(req) + if err != nil { + return err + } + rules = append(rules, respBody.Data...) + } + + resources := g.createResources(rules) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/folder.go b/providers/sumologic/folder.go new file mode 100644 index 000000000..e3cd843e9 --- /dev/null +++ b/providers/sumologic/folder.go @@ -0,0 +1,93 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type FolderGenerator struct { + SumoLogicService +} + +func (g *FolderGenerator) createResources(folders []sumologic.Folder) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(folders)) + + for i, folder := range folders { + title := strcase.ToSnake(replaceSpaceAndDash(folder.Name)) + + resource := terraformutils.NewSimpleResource( + folder.Id, + fmt.Sprintf("%s-%s", title, folder.Id), + "sumologic_folder", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *FolderGenerator) InitResources() error { + client := g.Client() + + var resources []terraformutils.Resource + + req := client.FolderManagementApi.GetPersonalFolder(g.AuthCtx()) + + respBody, _, err := client.FolderManagementApi.GetPersonalFolderExecute(req) + if err != nil { + return err + } + + personalFolder := *respBody + folders := g.getAllChildFolders(personalFolder) + + resources = g.createResources(folders) + g.Resources = resources + return nil +} + +func (g *FolderGenerator) getFolderOk(folderId string) (sumologic.Folder, bool) { + client := g.Client() + + req := client.FolderManagementApi.GetFolder(g.AuthCtx(), folderId) + folder, _, err := client.FolderManagementApi.GetFolderExecute(req) + if err != nil { + fmt.Println(err) + return sumologic.Folder{}, false + } + + return *folder, true +} + +func (g *FolderGenerator) getAllChildFolders(rootFolder sumologic.Folder) []sumologic.Folder { + var folders []sumologic.Folder + + for _, child := range rootFolder.Children { + if child.ItemType == "Folder" { + if folder, ok := g.getFolderOk(child.Id); ok { + folders = append(folders, folder) + folders = append(folders, g.getAllChildFolders(folder)...) + } + } + } + + return folders +} diff --git a/providers/sumologic/log_search.go b/providers/sumologic/log_search.go new file mode 100644 index 000000000..186670dad --- /dev/null +++ b/providers/sumologic/log_search.go @@ -0,0 +1,73 @@ +// Copyright 2023 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type LogSearchGenerator struct { + SumoLogicService +} + +func (g *LogSearchGenerator) createResources(logSearches []sumologic.LogSearch) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(logSearches)) + + for i, logSearch := range logSearches { + title := strcase.ToSnake(replaceSpaceAndDash(logSearch.Name)) + + resource := terraformutils.NewSimpleResource( + logSearch.Id, + fmt.Sprintf("%s-%s", title, logSearch.Id), + "sumologic_log_search", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *LogSearchGenerator) InitResources() error { + client := g.Client() + + var resources []terraformutils.Resource + var logSearches []sumologic.LogSearch + + req := client.LogSearchesManagementApi.ListLogSearches(g.AuthCtx()) + req = req.Limit(100) + + respBody, _, err := client.LogSearchesManagementApi.ListLogSearchesExecute(req) + if err != nil { + return err + } + logSearches = respBody.LogSearches + for respBody.Token != nil { + req = req.Token(respBody.GetToken()) + respBody, _, err = client.LogSearchesManagementApi.ListLogSearchesExecute(req) + if err != nil { + return err + } + logSearches = append(logSearches, respBody.LogSearches...) + } + + resources = g.createResources(logSearches) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/monitor.go b/providers/sumologic/monitor.go new file mode 100644 index 000000000..1ebb7905b --- /dev/null +++ b/providers/sumologic/monitor.go @@ -0,0 +1,66 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + "time" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type MonitorGenerator struct { + SumoLogicService +} + +func (g *MonitorGenerator) createResources(monitors []sumologic.MonitorsLibraryBaseResponse) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(monitors)) + + for i, monitor := range monitors { + name := strcase.ToSnake(replaceSpaceAndDash(monitor.Name)) + resource := terraformutils.NewSimpleResource( + monitor.Id, + fmt.Sprintf("%s-%s", name, monitor.Id), + "sumologic_monitor", + g.ProviderName, + []string{}, + ) + resources[i] = resource + } + + return resources +} + +func (g *MonitorGenerator) InitResources() error { + client := g.Client() + + searchReq := client.MonitorsLibraryManagementApi.MonitorsSearch( + g.AuthCtx()).Query(fmt.Sprintf("createdAfter:%d", time.Now().Unix())) + rspBody, _, err := client.MonitorsLibraryManagementApi.MonitorsSearchExecute(searchReq) + if err != nil { + return err + } + + var monitors []sumologic.MonitorsLibraryBaseResponse + for _, itemWithPath := range rspBody { + monitors = append(monitors, itemWithPath.Item) + } + + resources := g.createResources(monitors) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/partition.go b/providers/sumologic/partition.go new file mode 100644 index 000000000..874c3e21d --- /dev/null +++ b/providers/sumologic/partition.go @@ -0,0 +1,68 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type PartitionGenerator struct { + SumoLogicService +} + +func (g *PartitionGenerator) createResources(partitions []sumologic.Partition) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(partitions)) + + for i, partition := range partitions { + name := strcase.ToSnake(replaceSpaceAndDash(partition.Name)) + resource := terraformutils.NewSimpleResource( + partition.Id, + fmt.Sprintf("%s-%s", name, partition.Id), + "sumologic_partition", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *PartitionGenerator) InitResources() error { + client := g.Client() + req := client.PartitionManagementApi.ListPartitions(g.AuthCtx()) + req = req.Limit(100) + + respBody, _, err := client.PartitionManagementApi.ListPartitionsExecute(req) + if err != nil { + return err + } + partitions := respBody.Data + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.PartitionManagementApi.ListPartitionsExecute(req) + if err != nil { + return err + } + partitions = append(partitions, respBody.Data...) + } + + resources := g.createResources(partitions) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/role.go b/providers/sumologic/role.go new file mode 100644 index 000000000..fa8a311a6 --- /dev/null +++ b/providers/sumologic/role.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type RoleGenerator struct { + SumoLogicService +} + +func (g *RoleGenerator) createResources(roles []sumologic.RoleModel) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(roles)) + + for i, role := range roles { + name := strcase.ToSnake(replaceSpaceAndDash(role.Name)) + resource := terraformutils.NewSimpleResource( + role.Id, + fmt.Sprintf("%s-%s", name, role.Id), + "sumologic_role", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *RoleGenerator) InitResources() error { + client := g.Client() + req := client.RoleManagementApi.ListRoles(g.AuthCtx()) + req = req.Limit(100) + for _, filter := range g.Filter { + if filter.IsApplicable("role") && filter.FieldPath == "name" { + if len(filter.AcceptableValues) == 1 { + req = req.Name(filter.AcceptableValues[0]) + } + } + } + + respBody, _, err := client.RoleManagementApi.ListRolesExecute(req) + if err != nil { + return err + } + roles := respBody.Data + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.RoleManagementApi.ListRolesExecute(req) + if err != nil { + return err + } + roles = append(roles, respBody.Data...) + } + + resources := g.createResources(roles) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/sumologic_provider.go b/providers/sumologic/sumologic_provider.go new file mode 100644 index 000000000..bbc55462f --- /dev/null +++ b/providers/sumologic/sumologic_provider.go @@ -0,0 +1,155 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "errors" + "fmt" + "os" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/zclconf/go-cty/cty" +) + +type SumoLogicProvider struct { + terraformutils.Provider + AccessId string + AccessKey string + Environment string + baseUrl string +} + +var baseUrlMap = map[string]string{ + "au": "https://api.au.sumologic.com/api/", + "ca": "https://api.ca.sumologic.com/api/", + "de": "https://api.de.sumologic.com/api/", + "eu": "https://api.eu.sumologic.com/api/", + "fed": "https://api.fed.sumologic.com/api/", + "in": "https://api.in.sumologic.com/api/", + "jp": "https://api.jp.sumologic.com/api/", + "us1": "https://api.sumologic.com/api/", + "us2": "https://api.us2.sumologic.com/api/", +} + +func getBaseUrl(environment string) (string, error) { + env := strings.ToLower(environment) + if baseUrl, ok := baseUrlMap[env]; ok { + return baseUrl, nil + } else { + keys := []string{} + for k, _ := range baseUrlMap { + keys = append(keys, k) + } + return "", fmt.Errorf( + "invalid environment '%s', must be one of %s", environment, keys) + } +} + +func (p *SumoLogicProvider) Init(args []string) error { + if args[0] != "" { + p.AccessId = args[0] + } else if accessId := os.Getenv("SUMOLOGIC_ACCESS_ID"); accessId != "" { + p.AccessId = os.Getenv("SUMOLOGIC_ACCESS_ID") + } else { + return errors.New("accessId is not set") + } + + if args[1] != "" { + p.AccessKey = args[1] + } else if accessKey := os.Getenv("SUMOLOGIC_ACCESS_KEY"); accessKey != "" { + p.AccessKey = os.Getenv("SUMOLOGIC_ACCESS_KEY") + } else { + return errors.New("accessKey is not set") + } + + if args[2] != "" { + p.Environment = args[2] + } else if environment := os.Getenv("SUMOLOGIC_ENVIRONMENT"); environment != "" { + p.Environment = environment + if url, err := getBaseUrl(environment); err != nil { + return err + } else { + p.baseUrl = url + } + } else if baseUrl := os.Getenv("SUMOLOGIC_BASE_URL"); baseUrl != "" { + p.baseUrl = baseUrl + } else { + return errors.New("environment is not set") + } + + return nil +} + +func (p *SumoLogicProvider) GetName() string { + return "sumologic" +} + +func (p *SumoLogicProvider) GetConfig() cty.Value { + return cty.ObjectVal(map[string]cty.Value{ + "access_id": cty.StringVal(p.AccessId), + "access_key": cty.StringVal(p.AccessKey), + "environment": cty.StringVal(p.Environment), + "base_url": cty.StringVal(p.baseUrl), + }) +} + +func (p *SumoLogicProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator { + return map[string]terraformutils.ServiceGenerator{ + "connection": &ConnectionGenerator{}, + "dashboard": &DashboardGenerator{}, + "field_extraction_rule": &FieldExtractionRuleGenerator{}, + "log_search": &LogSearchGenerator{}, + "monitor": &MonitorGenerator{}, + "partition": &PartitionGenerator{}, + "role": &RoleGenerator{}, + "user": &UserGenerator{}, + } +} + +func (p *SumoLogicProvider) 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{}{ + "accessId": p.AccessId, + "accessKey": p.AccessKey, + "environment": p.Environment, + "baseUrl": p.baseUrl, + }) + + return nil +} + +func (p *SumoLogicProvider) GetProviderData(arg ...string) map[string]interface{} { + return map[string]interface{}{ + "provider": map[string]interface{}{ + "sumologic": map[string]interface{}{ + "accessId": p.AccessId, + "accessKey": p.AccessKey, + "environment": p.Environment, + }, + }, + } +} + +func (SumoLogicProvider) GetResourceConnections() map[string]map[string][]string { + return map[string]map[string][]string{} +} diff --git a/providers/sumologic/sumologic_service.go b/providers/sumologic/sumologic_service.go new file mode 100644 index 000000000..6a8a9e26e --- /dev/null +++ b/providers/sumologic/sumologic_service.go @@ -0,0 +1,56 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "context" + "log" + "strings" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type SumoLogicService struct { //nolint + terraformutils.Service +} + +func (s *SumoLogicService) Client() *sumologic.APIClient { + log.Printf("%s access id:%s, baseUrl:%s\n", + s.GetProviderName(), s.GetArgs()["accessId"].(string), s.GetArgs()["baseUrl"].(string)) + + config := sumologic.NewConfiguration() + config.Servers = []sumologic.ServerConfiguration{ + { + URL: strings.TrimSuffix(s.GetArgs()["baseUrl"].(string), "/"), + Description: "Base URL of the API Server", + Variables: make(map[string]sumologic.ServerVariable), + }, + } + client := sumologic.NewAPIClient(config) + return client +} + +func (s *SumoLogicService) AuthCtx() context.Context { + auth := context.WithValue(context.Background(), + sumologic.ContextBasicAuth, + sumologic.BasicAuth{ + UserName: s.GetArgs()["accessId"].(string), + Password: s.GetArgs()["accessKey"].(string), + }, + ) + return auth +} diff --git a/providers/sumologic/user.go b/providers/sumologic/user.go new file mode 100644 index 000000000..938cf3d46 --- /dev/null +++ b/providers/sumologic/user.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/terraformer/terraformutils" + "github.com/iancoleman/strcase" + sumologic "github.com/sumovishal/sumologic-go-sdk/api" +) + +type UserGenerator struct { + SumoLogicService +} + +func (g *UserGenerator) createResources(users []sumologic.UserModel) []terraformutils.Resource { + resources := make([]terraformutils.Resource, len(users)) + + for i, user := range users { + name := strcase.ToSnake(replaceSpaceAndDash(user.FirstName + "_" + user.LastName)) + resource := terraformutils.NewSimpleResource( + user.Id, + fmt.Sprintf("%s-%s", name, user.Id), + "sumologic_user", + g.ProviderName, + []string{}) + resources[i] = resource + } + + return resources +} + +func (g *UserGenerator) InitResources() error { + client := g.Client() + req := client.UserManagementApi.ListUsers(g.AuthCtx()) + req = req.Limit(100) + for _, filter := range g.Filter { + if filter.IsApplicable("user") && filter.FieldPath == "email" { + if len(filter.AcceptableValues) == 1 { + req = req.Email(filter.AcceptableValues[0]) + } + } + } + + respBody, _, err := client.UserManagementApi.ListUsersExecute(req) + if err != nil { + return err + } + users := respBody.Data + for respBody.Next != nil { + req = req.Token(respBody.GetNext()) + respBody, _, err = client.UserManagementApi.ListUsersExecute(req) + if err != nil { + return err + } + users = append(users, respBody.Data...) + } + + resources := g.createResources(users) + g.Resources = resources + return nil +} diff --git a/providers/sumologic/util.go b/providers/sumologic/util.go new file mode 100644 index 000000000..ac402e10d --- /dev/null +++ b/providers/sumologic/util.go @@ -0,0 +1,25 @@ +// Copyright 2022 The Terraformer Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sumologic + +import ( + "regexp" +) + +var regexSpaceAndDash = regexp.MustCompile("[- ]+") + +func replaceSpaceAndDash(str string) string { + return regexSpaceAndDash.ReplaceAllLiteralString(str, "_") +}