Skip to content

Commit 3c51cd4

Browse files
Merge pull request #332 from SumoLogic/gcp_metrics_custom_services
Bringing custom_services support for Gcp Metrics Source
2 parents 6564128 + 2c207e7 commit 3c51cd4

File tree

4 files changed

+134
-27
lines changed

4 files changed

+134
-27
lines changed

sumologic/resource_sumologic_gcp_metrics_source_test.go

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
1112
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
1213
"github.com/hashicorp/terraform-plugin-sdk/terraform"
1314
)
@@ -22,14 +23,15 @@ func TestAccSumologicGcpMetricsSource_create(t *testing.T) {
2223
var collector Collector
2324
cName, cDescription, cCategory := getRandomizedParams()
2425
sName, sDescription, sCategory := getRandomizedParams()
26+
customServicePrefix := acctest.RandomWithPrefix("compute.googleapis.com")
2527
GcpMetricsResourceName := "sumologic_gcp_metrics_source.gcp_metrics_source"
2628
resource.Test(t, resource.TestCase{
2729
PreCheck: func() { getServiceAccountCreds(t) },
2830
Providers: testAccProviders,
2931
CheckDestroy: testAccCheckGcpMetricsSourceDestroy,
3032
Steps: []resource.TestStep{
3133
{
32-
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sName, sDescription, sCategory),
34+
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sName, sDescription, sCategory, customServicePrefix),
3335
Check: resource.ComposeTestCheckFunc(
3436
testAccCheckGcpMetricsSourceExists(GcpMetricsResourceName, &GcpMetricsSource),
3537
testAccCheckGcpMetricsSourceValues(&GcpMetricsSource, sName, sDescription, sCategory),
@@ -41,6 +43,9 @@ func TestAccSumologicGcpMetricsSource_create(t *testing.T) {
4143
resource.TestCheckResourceAttr(GcpMetricsResourceName, "category", sCategory),
4244
resource.TestCheckResourceAttr(GcpMetricsResourceName, "content_type", "GcpMetrics"),
4345
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.type", "GcpMetricsPath"),
46+
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.custom_services.1.service_name", "compute_instance_and_guests"),
47+
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.custom_services.1.prefixes.0", customServicePrefix),
48+
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.custom_services.1.prefixes.1", "compute.googleapis.com/guest/"),
4449
),
4550
},
4651
},
@@ -54,14 +59,16 @@ func TestAccSumologicGcpMetricsSource_update(t *testing.T) {
5459
cName, cDescription, cCategory := getRandomizedParams()
5560
sName, sDescription, sCategory := getRandomizedParams()
5661
sNameUpdated, sDescriptionUpdated, sCategoryUpdated := getRandomizedParams()
62+
customServicePrefix := acctest.RandomWithPrefix("compute.googleapis.com")
63+
updatedCustomServicePrefix := acctest.RandomWithPrefix("compute.googleapis.com")
5764
GcpMetricsResourceName := "sumologic_gcp_metrics_source.gcp_metrics_source"
5865
resource.Test(t, resource.TestCase{
5966
PreCheck: func() { getServiceAccountCreds(t) },
6067
Providers: testAccProviders,
6168
CheckDestroy: testAccCheckHTTPSourceDestroy,
6269
Steps: []resource.TestStep{
6370
{
64-
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sName, sDescription, sCategory),
71+
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sName, sDescription, sCategory, customServicePrefix),
6572
Check: resource.ComposeTestCheckFunc(
6673
testAccCheckGcpMetricsSourceExists(GcpMetricsResourceName, &GcpMetricsSource),
6774
testAccCheckGcpMetricsSourceValues(&GcpMetricsSource, sName, sDescription, sCategory),
@@ -71,10 +78,11 @@ func TestAccSumologicGcpMetricsSource_update(t *testing.T) {
7178
resource.TestCheckResourceAttr(GcpMetricsResourceName, "category", sCategory),
7279
resource.TestCheckResourceAttr(GcpMetricsResourceName, "content_type", "GcpMetrics"),
7380
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.type", "GcpMetricsPath"),
81+
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.custom_services.1.prefixes.0", customServicePrefix),
7482
),
7583
},
7684
{
77-
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sNameUpdated, sDescriptionUpdated, sCategoryUpdated),
85+
Config: testAccSumologicGcpMetricsSourceConfig(t, cName, cDescription, cCategory, sNameUpdated, sDescriptionUpdated, sCategoryUpdated, updatedCustomServicePrefix),
7886
Check: resource.ComposeTestCheckFunc(
7987
testAccCheckGcpMetricsSourceExists(GcpMetricsResourceName, &GcpMetricsSource),
8088
testAccCheckGcpMetricsSourceValues(&GcpMetricsSource, sNameUpdated, sDescriptionUpdated, sCategoryUpdated),
@@ -84,6 +92,7 @@ func TestAccSumologicGcpMetricsSource_update(t *testing.T) {
8492
resource.TestCheckResourceAttr(GcpMetricsResourceName, "category", sCategoryUpdated),
8593
resource.TestCheckResourceAttr(GcpMetricsResourceName, "content_type", "GcpMetrics"),
8694
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.type", "GcpMetricsPath"),
95+
resource.TestCheckResourceAttr(GcpMetricsResourceName, "path.0.custom_services.1.prefixes.0", updatedCustomServicePrefix),
8796
),
8897
},
8998
},
@@ -195,7 +204,7 @@ func getServiceAccountCreds(t *testing.T) ServiceAccountCreds {
195204
return serviceAccountCreds
196205
}
197206

198-
func testAccSumologicGcpMetricsSourceConfig(t *testing.T, cName, cDescription, cCategory, sName, sDescription, sCategory string) string {
207+
func testAccSumologicGcpMetricsSourceConfig(t *testing.T, cName, cDescription, cCategory, sName, sDescription, sCategory, customServicePrefix string) string {
199208
cred := getServiceAccountCreds(t)
200209
srcStr := fmt.Sprintf(`
201210
resource "sumologic_collector" "test" {
@@ -207,33 +216,46 @@ func testAccSumologicGcpMetricsSourceConfig(t *testing.T, cName, cDescription, c
207216
name = "%s"
208217
description = "%s"
209218
category = "%s"
210-
content_type = "GcpMetrics"
219+
content_type = "GcpMetrics"
211220
scan_interval = 300000
212-
paused = false
221+
paused = false
213222
collector_id = "${sumologic_collector.test.id}"
223+
filters {
224+
name = "Exclude Comments"
225+
filter_type = "Exclude"
226+
regexp = "#.*"
227+
}
214228
authentication {
215-
type = "%s"
216-
project_id = "%s"
217-
private_key_id = "%s"
218-
private_key = <<EOPK
229+
type = "%s"
230+
project_id = "%s"
231+
private_key_id = "%s"
232+
private_key = <<EOPK
219233
%sEOPK
220-
client_email = "%s"
221-
client_id = "%s"
222-
auth_uri = "%s"
223-
token_uri = "%s"
224-
auth_provider_x509_cert_url = "%s"
225-
client_x509_cert_url = "%s"
226-
}
227-
path {
234+
client_email = "%s"
235+
client_id = "%s"
236+
auth_uri = "%s"
237+
token_uri = "%s"
238+
auth_provider_x509_cert_url = "%s"
239+
client_x509_cert_url = "%s"
240+
}
241+
path {
228242
type = "GcpMetricsPath"
229-
limit_to_regions = ["asia-south1"]
230-
limit_to_services = ["Compute Engine", "CloudSQL"]
231-
}
232-
lifecycle {
243+
limit_to_regions = ["asia-south1"]
244+
limit_to_services = ["Compute Engine", "CloudSQL"]
245+
custom_services {
246+
service_name = "mysql"
247+
prefixes = ["cloudsql.googleapis.com/database/mysql/","cloudsql.googleapis.com/database/memory/","cloudsql.googleapis.com/database/cpu","cloudsql.googleapis.com/database/disk"]
248+
}
249+
custom_services {
250+
service_name = "compute_instance_and_guests"
251+
prefixes = ["%s" ,"compute.googleapis.com/guest/", "compute.googleapis.com/instance/"]
252+
}
253+
}
254+
lifecycle {
233255
ignore_changes = [authentication[0].private_key]
234-
}
235256
}
257+
}
236258
`, cName, cDescription, cCategory, sName, sDescription, sCategory,
237-
cred.Type, cred.ProjectId, cred.PrivateKeyId, cred.PrivateKey, cred.ClientEmail, cred.ClientId, cred.AuthUri, cred.TokenUri, cred.AuthProviderX509CertUrl, cred.ClientX509CertUrl)
259+
cred.Type, cred.ProjectId, cred.PrivateKeyId, cred.PrivateKey, cred.ClientEmail, cred.ClientId, cred.AuthUri, cred.TokenUri, cred.AuthProviderX509CertUrl, cred.ClientX509CertUrl, customServicePrefix)
238260
return srcStr
239261
}

sumologic/resource_sumologic_generic_polling_source.go

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"log"
77
"strconv"
8+
"strings"
89

910
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
1011
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
@@ -149,7 +150,25 @@ func resourceSumologicGenericPollingSource() *schema.Resource {
149150
Type: schema.TypeString,
150151
},
151152
},
152-
153+
"custom_services": {
154+
Type: schema.TypeList,
155+
Optional: true,
156+
Elem: &schema.Resource{
157+
Schema: map[string]*schema.Schema{
158+
"service_name": {
159+
Type: schema.TypeString,
160+
Optional: true,
161+
},
162+
"prefixes": {
163+
Type: schema.TypeList,
164+
Optional: true,
165+
Elem: &schema.Schema{
166+
Type: schema.TypeString,
167+
},
168+
},
169+
},
170+
},
171+
},
153172
"tag_filters": {
154173
Type: schema.TypeList,
155174
Optional: true,
@@ -317,6 +336,7 @@ func getPollingThirdPartyPathAttributes(pollingResource []PollingResource) []map
317336
"limit_to_regions": t.Path.LimitToRegions,
318337
"limit_to_namespaces": t.Path.LimitToNamespaces,
319338
"limit_to_services": t.Path.LimitToServices,
339+
"custom_services": flattenCustomServices(t.Path.CustomServices),
320340
"tag_filters": flattenPollingTagFilters(t.Path.TagFilters),
321341
"sns_topic_or_subscription_arn": flattenPollingSnsTopicOrSubscriptionArn(t.Path.SnsTopicOrSubscriptionArn),
322342
}
@@ -351,6 +371,38 @@ func getPollingThirdPartyAuthenticationAttributes(pollingResource []PollingResou
351371
return s
352372
}
353373

374+
func flattenCustomServices(v []string) []map[string]interface{} {
375+
var custom_services []map[string]interface{}
376+
for _, d := range v {
377+
custom_service_name_and_prefixes := strings.Split(d, "=")
378+
custom_service_name := custom_service_name_and_prefixes[0]
379+
custom_service_prefixes := strings.Split(custom_service_name_and_prefixes[1], ";")
380+
custom_service := map[string]interface{}{
381+
"service_name": custom_service_name,
382+
"prefixes": custom_service_prefixes,
383+
}
384+
custom_services = append(custom_services, custom_service)
385+
}
386+
return custom_services
387+
}
388+
389+
func getCustomServices(path map[string]interface{}) []string {
390+
var customServices []string
391+
rawCustomServicesConfig := path["custom_services"].([]interface{})
392+
for _, rawCustomServiceConfig := range rawCustomServicesConfig {
393+
customServiceConfig := rawCustomServiceConfig.(map[string]interface{})
394+
customServiceName := customServiceConfig["service_name"].(string)
395+
customServicePrefixesInterface := customServiceConfig["prefixes"].([]interface{})
396+
var customServicePrefixes []string
397+
for _, v := range customServicePrefixesInterface {
398+
customServicePrefixes = append(customServicePrefixes, v.(string))
399+
}
400+
customServices = append(customServices,
401+
fmt.Sprintf("%s=%s", customServiceName, strings.Join(customServicePrefixes[:], ";")))
402+
}
403+
return customServices
404+
}
405+
354406
func flattenPollingTagFilters(v []TagFilter) []map[string]interface{} {
355407
var filters []map[string]interface{}
356408
for _, d := range v {
@@ -415,7 +467,7 @@ func getPollingSnsTopicOrSubscriptionArn(d *schema.ResourceData) PollingSnsTopic
415467
return snsTopicOrSubscriptionArn
416468
}
417469

418-
func addGcpServiceAccountDetailsToAuth(authSettings *PollingAuthentication, auth map[string]interface{}) {
470+
func addGcpServiceAccountDetailsToAuth(authSettings *PollingAuthentication, auth map[string]interface{}) error {
419471
authSettings.Type = "service_account"
420472
authSettings.ProjectId = auth["project_id"].(string)
421473
authSettings.PrivateKeyId = auth["private_key_id"].(string)
@@ -426,6 +478,23 @@ func addGcpServiceAccountDetailsToAuth(authSettings *PollingAuthentication, auth
426478
authSettings.TokenUrl = auth["token_uri"].(string)
427479
authSettings.AuthProviderX509CertUrl = auth["auth_provider_x509_cert_url"].(string)
428480
authSettings.ClientX509CertUrl = auth["client_x509_cert_url"].(string)
481+
482+
errTxt := ""
483+
if len(strings.Trim(authSettings.ProjectId, " \t")) == 0 {
484+
errTxt = errTxt + "\nproject_id is mandator while using service_account authentication"
485+
}
486+
if len(authSettings.ClientEmail) == 0 {
487+
errTxt = errTxt + "\nclient_email is mandator while using service_account authentication"
488+
}
489+
if len(authSettings.PrivateKey) == 0 {
490+
errTxt = errTxt + "\nprivate_key is mandator while using service_account authentication"
491+
}
492+
493+
if len(errTxt) == 0 {
494+
return nil
495+
} else {
496+
return errors.New(errTxt)
497+
}
429498
}
430499

431500
func getPollingAuthentication(d *schema.ResourceData) (PollingAuthentication, error) {
@@ -453,7 +522,10 @@ func getPollingAuthentication(d *schema.ResourceData) (PollingAuthentication, er
453522
authSettings.Region = auth["region"].(string)
454523
}
455524
case "service_account":
456-
addGcpServiceAccountDetailsToAuth(&authSettings, auth)
525+
err := addGcpServiceAccountDetailsToAuth(&authSettings, auth)
526+
if err != nil {
527+
return authSettings, err
528+
}
457529

458530
default:
459531
errorMessage := fmt.Sprintf("[ERROR] Unknown authType: %v", authType)
@@ -486,6 +558,7 @@ func getLimitToServices(path map[string]interface{}) []string {
486558
func addGcpMetricsPathSettings(pathSettings *PollingPath, path map[string]interface{}) {
487559
pathSettings.LimitToRegions = getLimitToRegions(path)
488560
pathSettings.LimitToServices = getLimitToServices(path)
561+
pathSettings.CustomServices = getCustomServices(path)
489562
}
490563

491564
func getPollingPathSettings(d *schema.ResourceData) (PollingPath, error) {

sumologic/sumologic_polling_source.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type PollingPath struct {
4848
LimitToRegions []string `json:"limitToRegions,omitempty"`
4949
LimitToNamespaces []string `json:"limitToNamespaces,omitempty"`
5050
LimitToServices []string `json:"limitToServices,omitempty"`
51+
CustomServices []string `json:"customServices,omitempty"`
5152
TagFilters []TagFilter `json:"tagFilters,omitempty"`
5253
SnsTopicOrSubscriptionArn PollingSnsTopicOrSubscriptionArn `json:"snsTopicOrSubscriptionArn,omitempty"`
5354
}

website/docs/r/gcp_metrics_source.html.markdown

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ EOPK
4141
type = "GcpMetricsPath"
4242
limit_to_regions = ["us-east1", "us-central1", "asia-south1"]
4343
limit_to_services = ["Compute Engine", "Firebase", "App Engine"]
44+
custom_services = {
45+
service_name = "mysql"
46+
prefixes = ["cloudsql.googleapis.com/database/mysql/","cloudsql.googleapis.com/database/memory/","cloudsql.googleapis.com/database/cpu","cloudsql.googleapis.com/database/disk"]
47+
}
48+
custom_services = {
49+
service_name = "compute_instance_and_guests"
50+
prefixes = ["compute.googleapis.com/instance/","compute.googleapis.com/guest/"]
51+
}
4452
}
4553
4654
lifecycle {
@@ -77,6 +85,9 @@ In addition to the [Common Source Properties](https://registry.terraform.io/prov
7785
+ `type` - (Required) Type of polling source. This has to be `GcpMetricsPath`.
7886
+ `limit_to_regions` - (Optional) List of regions for which metrics would be collected (Empty to collect from all regions)
7987
+ `limit_to_services` - (Required) List of services from which metrics would be collected
88+
+ `custom_services` - (Optional) Sumoloigc provides list of services that can be used in limit_to_services for which metrics would be collected. Custom Services allow you to define your own service w.r.t. metric collection. You can provide list of metric prefixes that should be collected as part of the custom service. This provides fine-grain control w.r.t. what all metrics are ingested by sumologic.
89+
+ `service_name` - Name of the custom service you want to define.
90+
+ `prefixes` - List of metric type prefixes. Eg: `["compute.googleapis.com/instance/","compute.googleapis.com/guest/"]`
8091
- `lifecycle` - (Required) describe fields that should be ignored by terraform while doing comparision i.e. Sumologic backend will return `private_key` as `********`
8192

8293
### See also

0 commit comments

Comments
 (0)