Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sysdig/internal/client/v2/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,11 @@ type PostureZoneRequest struct {
Scopes []PostureZoneScope `json:"scopes"`
}

type ZonePoliciesRequest struct {
ZoneID int `json:"zoneId"`
PolicyIDs []int `json:"policyIds"`
}

type PostureZoneResponse struct {
Data PostureZone `json:"data"`
}
Expand Down
31 changes: 29 additions & 2 deletions sysdig/internal/client/v2/posture_zones.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import (
)

const (
PostureZonesPath = "%s/api/cspm/v1/policy/zones"
PostureZonePath = "%s/api/cspm/v1/policy/zones/%d"
PostureZonesPath = "%s/api/cspm/v1/policy/zones"
PostureZonePath = "%s/api/cspm/v1/policy/zones/%d"
PostureZonePoliciesPath = "%s/api/cspm/v1/policy/zone-policies"
)

type PostureZoneInterface interface {
Base
CreateOrUpdatePostureZone(ctx context.Context, z *PostureZoneRequest) (*PostureZone, string, error)
GetPostureZone(ctx context.Context, id int) (*PostureZone, error)
DeletePostureZone(ctx context.Context, id int) error
BindZoneToPolicies(ctx context.Context, r *ZonePoliciesRequest) error
}

func (client *Client) CreateOrUpdatePostureZone(ctx context.Context, r *PostureZoneRequest) (*PostureZone, string, error) {
Expand Down Expand Up @@ -76,10 +78,35 @@ func (client *Client) DeletePostureZone(ctx context.Context, id int) error {
return nil
}

func (client *Client) BindZoneToPolicies(ctx context.Context, r *ZonePoliciesRequest) error {

payload, err := Marshal(r)
if err != nil {
return err
}

response, err := client.requester.Request(ctx, http.MethodPost, client.getZonePoliciesURL(), payload)
if err != nil {
return err
}

defer response.Body.Close()

if response.StatusCode != http.StatusOK {
return client.ErrorFromResponse(response)
}

return nil
}

func (client *Client) createPostureZoneURL() string {
return fmt.Sprintf(PostureZonesPath, client.config.url)
}

func (client *Client) getPostureZoneURL(id int) string {
return fmt.Sprintf(PostureZonePath, client.config.url, id)
}

func (client *Client) getZonePoliciesURL() string {
return fmt.Sprintf(PostureZonePoliciesPath, client.config.url)
}
189 changes: 159 additions & 30 deletions sysdig/resource_sysdig_secure_posture_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package sysdig

import (
"context"
"fmt"
"github.com/rs/zerolog/log"
"strconv"
"time"

Expand All @@ -14,8 +16,8 @@ func resourceSysdigSecurePostureZone() *schema.Resource {
timeout := 5 * time.Minute

return &schema.Resource{
CreateContext: resourceCreateOrUpdatePostureZone,
UpdateContext: resourceCreateOrUpdatePostureZone,
CreateContext: resourceCreatePostureZone,
UpdateContext: resourceUpdatePostureZone,
DeleteContext: resourceSysdigSecurePostureZoneDelete,
ReadContext: resourceSysdigSecurePostureZoneRead,
Importer: &schema.ResourceImporter{
Expand Down Expand Up @@ -105,48 +107,119 @@ func getPostureZoneClient(c SysdigClients) (v2.PostureZoneInterface, error) {
return client, nil
}

func resourceCreateOrUpdatePostureZone(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
policiesData := d.Get(SchemaPolicyIDsKey).(*schema.Set).List()
policies := make([]string, len(policiesData))
for i, p := range policiesData {
policies[i] = strconv.Itoa(p.(int))
func resourceCreatePostureZone(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
policies, err := getPolicies(d)
if err != nil {
return diag.FromErr(err)
}

scopesList := d.Get(SchemaScopesKey).(*schema.Set).List()
scopes := make([]v2.PostureZoneScope, 0)
if len(scopesList) > 0 {
scopeList := scopesList[0].(map[string]interface{})[SchemaScopeKey].(*schema.Set).List()
for _, attr := range scopeList {
s := attr.(map[string]interface{})
scopes = append(scopes, v2.PostureZoneScope{
TargetType: s[SchemaTargetTypeKey].(string),
Rules: s[SchemaRulesKey].(string),
})
}
scopes, err := getScopes(d)
if err != nil {
return diag.FromErr(err)
}

req := &v2.PostureZoneRequest{
ID: d.Id(),
zoneClient, err := getZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}
postureZoneClient, err := getPostureZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

zoneRequest := &v2.ZoneRequest{
Name: d.Get(SchemaNameKey).(string),
Description: d.Get(SchemaDescriptionKey).(string),
PolicyIDs: policies,
Scopes: scopes,
}

zoneClient, err := getPostureZoneClient(meta.(SysdigClients))
zone, err := zoneClient.CreateZone(ctx, zoneRequest)
if err != nil {
return diag.Errorf("Error creating resource: %s", err)
}

policyIDs, err := convertPoliciesToInt(policies)
if err != nil {
return diag.FromErr(err)
}

zone, errStatus, err := zoneClient.CreateOrUpdatePostureZone(ctx, req)
req := &v2.ZonePoliciesRequest{
ZoneID: zone.ID,
PolicyIDs: policyIDs,
}

err = postureZoneClient.BindZoneToPolicies(ctx, req)
if err != nil {
return diag.Errorf("Error creating resource: %s %s", errStatus, err)
log.Err(err).Int("zone_id", zone.ID).Msg("Error attaching zone to policies... deleting created zone")
err2 := zoneClient.DeleteZone(ctx, zone.ID)
if err2 != nil {
return diag.Errorf("Error deleting zone [zone ID = %d] after failed attaching to policies: %s", zone.ID, err2)
}
return diag.Errorf("Error attaching zone to policies: %s", err)
}

d.SetId(zone.ID)
d.SetId(strconv.Itoa(zone.ID))
return resourceSysdigSecurePostureZoneRead(ctx, d, meta)
}

resourceSysdigSecurePostureZoneRead(ctx, d, meta)
return nil
func resourceUpdatePostureZone(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
policies, err := getPolicies(d)
if err != nil {
return diag.FromErr(err)
}

scopes, err := getScopes(d)
if err != nil {
return diag.FromErr(err)
}

zoneClient, err := getZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}
postureZoneClient, err := getPostureZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

id, err := strconv.Atoi(d.Id())
if err != nil {
return diag.Errorf("Error updating posture zone resource, ID is not integer: %s", d.Id())
}

zoneRequest := &v2.ZoneRequest{
ID: id,
Name: d.Get(SchemaNameKey).(string),
Description: d.Get(SchemaDescriptionKey).(string),
Scopes: scopes,
}

if d.HasChange(SchemaNameKey) || d.HasChange(SchemaDescriptionKey) || d.HasChange(SchemaScopesKey) {
_, err = zoneClient.UpdateZone(ctx, zoneRequest)
if err != nil {
return diag.Errorf("Error updating resource: %s", err)
}
}

policyIDs, err := convertPoliciesToInt(policies)
if err != nil {
return diag.FromErr(err)
}

if d.HasChange(SchemaPolicyIDsKey) {
req := &v2.ZonePoliciesRequest{
ZoneID: id,
PolicyIDs: policyIDs,
}

err = postureZoneClient.BindZoneToPolicies(ctx, req)
if err != nil {
log.Err(err).Int("zone_id", id).Msg("Error attaching zone to policies")
return diag.Errorf("Error attaching zone to policies: %s", err)
}
}

return resourceSysdigSecurePostureZoneRead(ctx, d, meta)
}

func resourceSysdigSecurePostureZoneRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand Down Expand Up @@ -225,7 +298,11 @@ func resourceSysdigSecurePostureZoneRead(ctx context.Context, d *schema.Resource
}

func resourceSysdigSecurePostureZoneDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := getPostureZoneClient(meta.(SysdigClients))
postureClient, err := getPostureZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}
zoneClient, err := getZoneClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}
Expand All @@ -235,10 +312,62 @@ func resourceSysdigSecurePostureZoneDelete(ctx context.Context, d *schema.Resour
return diag.FromErr(err)
}

err = client.DeletePostureZone(ctx, id)
err = removeZoneFromPolicies(ctx, postureClient, id)
if err != nil {
return diag.FromErr(err)
return diag.Errorf("Error removing zone from policies: %s", err)
}

err = zoneClient.DeleteZone(ctx, id)
if err != nil {

return diag.Errorf("Error deleting zone: %s", err)
}

return nil
}

func removeZoneFromPolicies(ctx context.Context, client v2.PostureZoneInterface, zoneID int) error {
req := &v2.ZonePoliciesRequest{
ZoneID: zoneID,
PolicyIDs: []int{},
}

return client.BindZoneToPolicies(ctx, req)
}

func getPolicies(d *schema.ResourceData) ([]string, error) {
policiesData := d.Get(SchemaPolicyIDsKey).(*schema.Set).List()
policies := make([]string, len(policiesData))
for i, p := range policiesData {
policies[i] = strconv.Itoa(p.(int))
}
return policies, nil
}

func getScopes(d *schema.ResourceData) ([]v2.ZoneScope, error) {
scopesList := d.Get(SchemaScopesKey).(*schema.Set).List()
scopes := make([]v2.ZoneScope, 0)
if len(scopesList) > 0 {
scopeList := scopesList[0].(map[string]interface{})[SchemaScopeKey].(*schema.Set).List()
for _, attr := range scopeList {
s := attr.(map[string]interface{})
scopes = append(scopes, v2.ZoneScope{
TargetType: s[SchemaTargetTypeKey].(string),
Rules: s[SchemaRulesKey].(string),
})
}
}
return scopes, nil
}

func convertPoliciesToInt(policies []string) ([]int, error) {
policyIDs := make([]int, len(policies))
for i, p := range policies {
id, err := strconv.Atoi(p)
if err != nil {
return nil, fmt.Errorf("error converting policy ID to int: %s", err)
}
policyIDs[i] = id
}
return policyIDs, nil
}
Loading