Skip to content
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
)

require (
dario.cat/mergo v1.0.1 // indirect
github.com/ProtonMail/go-crypto v1.4.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
Expand All @@ -31,6 +32,7 @@ require (
github.com/docker/docker-credential-helpers v0.9.5 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/go-akka/configuration v0.0.0-20200606091224-a002c0330665 // indirect
github.com/go-test/deep v1.0.8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.21.2 // indirect
Expand Down Expand Up @@ -80,5 +82,6 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.79.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
11 changes: 6 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg=
github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
Expand Down Expand Up @@ -57,8 +57,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
Expand Down Expand Up @@ -295,8 +295,9 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
Expand Down
5 changes: 5 additions & 0 deletions sysdig/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const (
SchemaScopeKey = "scope"
SchemaScopesKey = "scopes"
SchemaTargetTypeKey = "target_type"
SchemaExpressionKey = "expression"
Comment thread
tembleking marked this conversation as resolved.
SchemaFieldKey = "field"
SchemaOperatorKey = "operator"
SchemaValueKey = "value"
SchemaValuesKey = "values"
SchemaRoleKey = "role"
SchemaSystemRoleKey = "system_role"
SchemaRulesKey = "rules"
Expand Down
81 changes: 65 additions & 16 deletions sysdig/data_source_sysdig_secure_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,34 @@ func dataSourceSysdigSecureZone() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
// Not marked Deprecated: rules with v2-compatible syntax are fully supported.
// Only v1 syntax (labels, labelValues, agentTags) is deprecated, but since
// this is a Computed field, SDK v2 has no mechanism for conditional deprecation.
// The resource-side ValidateDiagFunc handles the v1-only warning.
SchemaRulesKey: {
Type: schema.TypeString,
Computed: true,
},
SchemaExpressionKey: {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
SchemaFieldKey: {Type: schema.TypeString, Computed: true},
SchemaOperatorKey: {Type: schema.TypeString, Computed: true},
SchemaValueKey: {Type: schema.TypeString, Computed: true},
SchemaValuesKey: {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
},
},
},

"id": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -74,52 +95,80 @@ func dataSourceSysdigSecureZone() *schema.Resource {
}

func dataSourceSysdigSecureZoneRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
client, err := getZoneClient(m.(SysdigClients))
clientV2, err := getZoneV2Client(m.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

var zone *v2.Zone
var zoneV2 *v2.ZoneV2
zoneIDRaw, hasZoneID := d.GetOk("id")
if hasZoneID {
zoneID, err := strconv.Atoi(zoneIDRaw.(string))
if err != nil {
return diag.FromErr(fmt.Errorf("invalid zone id: %s", err))
}
zone, err = client.GetZoneByID(ctx, zoneID)
zoneV2, err = clientV2.GetZoneV2(ctx, zoneID)
if err != nil {
return diag.FromErr(fmt.Errorf("error fetching zone by ID: %s", err))
return diag.FromErr(fmt.Errorf("error fetching zone v2 by ID: %s", err))
}
} else if nameRaw, hasName := d.GetOk("name"); hasName {
name := nameRaw.(string)
zones, err := client.GetZones(ctx, name)
zones, err := clientV2.GetZonesV2(ctx, name)
if err != nil {
return diag.FromErr(fmt.Errorf("error fetching zones: %s", err))
}
for _, z := range zones {
if z.Name == name {
zone = &z
zoneV2 = &z
break
}
}
if zone == nil {
if zoneV2 == nil {
return diag.FromErr(fmt.Errorf("zone with name '%s' not found", name))
}
zoneV2, err = clientV2.GetZoneV2(ctx, zoneV2.ID)
if err != nil {
return diag.FromErr(fmt.Errorf("error fetching zone by name: %s", err))
}
} else {
return diag.FromErr(fmt.Errorf("either id or name must be specified"))
}

d.SetId(fmt.Sprintf("%d", zone.ID))
_ = d.Set(SchemaNameKey, zone.Name)
_ = d.Set(SchemaDescriptionKey, zone.Description)
_ = d.Set(SchemaIsSystemKey, zone.IsSystem)
_ = d.Set(SchemaAuthorKey, zone.Author)
_ = d.Set(SchemaLastModifiedBy, zone.LastModifiedBy)
_ = d.Set(SchemaLastUpdated, time.UnixMilli(zone.LastUpdated).Format(time.RFC3339))
d.SetId(fmt.Sprintf("%d", zoneV2.ID))
_ = d.Set(SchemaNameKey, zoneV2.Name)
_ = d.Set(SchemaDescriptionKey, zoneV2.Description)
_ = d.Set(SchemaIsSystemKey, zoneV2.IsSystem)
_ = d.Set(SchemaAuthorKey, zoneV2.Author)
_ = d.Set(SchemaLastModifiedBy, zoneV2.LastModifiedBy)
_ = d.Set(SchemaLastUpdated, time.UnixMilli(zoneV2.LastUpdated).Format(time.RFC3339))

if err := d.Set(SchemaScopeKey, fromZoneScopesResponse(zone.Scopes)); err != nil {
if err := d.Set(SchemaScopeKey, getZoneScopes(zoneV2)); err != nil {
return diag.FromErr(fmt.Errorf("error setting scope: %s", err))
}

return nil
}

func getZoneScopes(zoneV2 *v2.ZoneV2) []any {
// Build expression lookup by filter ID from the v2 response.
out := make([]any, 0)
if zoneV2 != nil {
for _, s := range zoneV2.Scopes {
for _, f := range s.Filters {
if f.ID != 0 && (len(f.Expressions) > 0 || f.Rules != "") {
var exprs []any
for _, e := range f.Expressions {
exprs = append(exprs, flattenExpressionV2(e))
}
m := map[string]any{
SchemaIDKey: f.ID,
SchemaTargetTypeKey: f.ResourceType,
SchemaRulesKey: f.Rules,
}
m[SchemaExpressionKey] = exprs
out = append(out, m)
}
}
}
}
return out
}
120 changes: 120 additions & 0 deletions sysdig/data_source_sysdig_secure_zone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package sysdig_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
Expand Down Expand Up @@ -43,6 +44,125 @@ func TestAccDataSourceSysdigSecureZone(t *testing.T) {
})
}

func TestAccDataSourceSysdigSecureZone_ByName(t *testing.T) {
zoneName := "Zone_DS_" + randomText(5)

resource.ParallelTest(t, resource.TestCase{
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
ProviderFactories: map[string]func() (*schema.Provider, error){
"sysdig": func() (*schema.Provider, error) {
return sysdig.Provider(), nil
},
},
Steps: []resource.TestStep{
{
Config: testAccDataSourceSecureZoneByName(zoneName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.sysdig_secure_zone.test",
"name",
zoneName,
),
resource.TestCheckResourceAttr(
"data.sysdig_secure_zone.test",
"scope.0.target_type",
"aws",
),

// v2 expressions
resource.TestCheckResourceAttr(
"data.sysdig_secure_zone.test",
"scope.0.expression.#",
"1",
),
resource.TestCheckResourceAttr(
"data.sysdig_secure_zone.test",
"scope.0.expression.0.field",
"organization",
),
),
},
},
})
}

func TestAccDataSourceSysdigSecureZone_ByID(t *testing.T) {
zoneName := "Zone_DS_ID_" + randomText(5)

resource.ParallelTest(t, resource.TestCase{
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
ProviderFactories: map[string]func() (*schema.Provider, error){
"sysdig": func() (*schema.Provider, error) {
return sysdig.Provider(), nil
},
},
Steps: []resource.TestStep{
{
Config: testAccDataSourceSecureZoneByID(zoneName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"data.sysdig_secure_zone.test",
"id",
),
resource.TestCheckResourceAttr(
"data.sysdig_secure_zone.test",
"scope.0.expression.#",
"1",
),
),
},
},
})
}

func testAccDataSourceSecureZoneByName(name string) string {
return fmt.Sprintf(`
resource "sysdig_secure_zone" "test" {
name = "%s"
description = "ds acceptance test"

scope {
target_type = "aws"

expression {
field = "organization"
operator = "in"
values = ["o1", "o2"]
}
}
}

data "sysdig_secure_zone" "test" {
depends_on = [sysdig_secure_zone.test]
name = "%s"
}
`, name, name)
}

func testAccDataSourceSecureZoneByID(name string) string {
return fmt.Sprintf(`
resource "sysdig_secure_zone" "test" {
name = "%s"
description = "ds acceptance test"

scope {
target_type = "aws"

expression {
field = "organization"
operator = "in"
values = ["o1", "o2"]
}
}
}

data "sysdig_secure_zone" "test" {
depends_on = [sysdig_secure_zone.test]
id = sysdig_secure_zone.test.id
}
`, name)
}

func testAccDataSourceSysdigSecureZoneConfig() string {
return `
resource "sysdig_secure_zone" "sample" {
Expand Down
55 changes: 55 additions & 0 deletions sysdig/data_source_sysdig_secure_zone_unit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package sysdig

import (
"testing"

v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"
)

func TestGetZoneScopes_MatchByID(t *testing.T) {
zoneV2 := &v2.ZoneV2{
Scopes: []v2.ScopeV2{
{
Filters: []v2.FilterV2{
{
ID: 10,
ResourceType: "kubernetes",
Expressions: []v2.ExpressionV2{
{Field: "cluster", Operator: "in", Values: []string{"a"}},
},
},
{
ID: 20,
ResourceType: "kubernetes",
Expressions: []v2.ExpressionV2{
{Field: "cluster", Operator: "in", Values: []string{"b"}},
},
},
},
},
},
}

result := getZoneScopes(zoneV2)
if len(result) != 2 {
t.Fatalf("expected 2 scopes, got %d", len(result))
}

// Verify each scope got its own expressions by checking the ID-expression pairing.
for _, raw := range result {
scope := raw.(map[string]any)
id := scope[SchemaIDKey].(int)
exprs, ok := scope[SchemaExpressionKey].([]any)
if !ok || len(exprs) != 1 {
t.Fatalf("scope ID=%d: expected 1 expression, got %v", id, scope[SchemaExpressionKey])
}
expr := exprs[0].(map[string]any)
vals := expr["values"].([]string)
if id == 10 && vals[0] != "a" {
t.Errorf("scope ID=10: expected values [a], got %v", vals)
}
if id == 20 && vals[0] != "b" {
t.Errorf("scope ID=20: expected values [b], got %v", vals)
}
}
}
Loading
Loading