Skip to content

Commit 036d69a

Browse files
feat: Add secure CloudAccount resource (#111)
* add secure cloudAccount resource * use correct json field * correct query param, mark field as computed * clear ID on read error
1 parent 75eb3d8 commit 036d69a

File tree

8 files changed

+327
-76
lines changed

8 files changed

+327
-76
lines changed

go.mod

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@ require (
66
cloud.google.com/go v0.76.0 // indirect
77
cloud.google.com/go/storage v1.13.0 // indirect
88
github.com/agext/levenshtein v1.2.3 // indirect
9-
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
10-
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 // indirect
119
github.com/apparentlymart/go-cidr v1.1.0 // indirect
1210
github.com/aws/aws-sdk-go v1.37.10 // indirect
1311
github.com/fatih/color v1.12.0 // indirect
1412
github.com/hashicorp/errwrap v1.1.0 // indirect
15-
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
1613
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
1714
github.com/hashicorp/go-hclog v0.16.2 // indirect
1815
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -24,7 +21,6 @@ require (
2421
github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0
2522
github.com/hashicorp/yamux v0.0.0-20210707203944-259a57b3608c // indirect
2623
github.com/jmespath/go-jmespath v0.4.0
27-
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba // indirect
2824
github.com/klauspost/compress v1.11.7 // indirect
2925
github.com/mattn/go-isatty v0.0.13 // indirect
3026
github.com/mitchellh/go-testing-interface v1.14.1 // indirect

go.sum

Lines changed: 18 additions & 72 deletions
Large diffs are not rendered by default.

sysdig/internal/client/secure/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ type SysdigSecureClient interface {
5252
GetVulnerabilityExceptionByID(context.Context, string, string) (*VulnerabilityException, error)
5353
DeleteVulnerabilityException(context.Context, string, string) error
5454
UpdateVulnerabilityException(context.Context, string, *VulnerabilityException) (*VulnerabilityException, error)
55+
56+
CreateCloudAccount(context.Context, *CloudAccount) (*CloudAccount, error)
57+
GetCloudAccountById(context.Context, string) (*CloudAccount, error)
58+
DeleteCloudAccount(context.Context, string) error
59+
UpdateCloudAccount(context.Context, string, *CloudAccount) (*CloudAccount, error)
5560
}
5661

5762
func WithExtraHeaders(client SysdigSecureClient, extraHeaders map[string]string) SysdigSecureClient {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package secure
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
)
9+
10+
func (client *sysdigSecureClient) cloudAccountURL(includeExternalID bool) string {
11+
if includeExternalID {
12+
return fmt.Sprintf("%s/api/cloud/v2/accounts?includeExternalID=true", client.URL)
13+
}
14+
return fmt.Sprintf("%s/api/cloud/v2/accounts", client.URL)
15+
}
16+
17+
func (client *sysdigSecureClient) cloudAccountByIdURL(accountID string, includeExternalID bool) string {
18+
if includeExternalID {
19+
return fmt.Sprintf("%s/api/cloud/v2/accounts/%s?includeExternalID=true", client.URL, accountID)
20+
}
21+
return fmt.Sprintf("%s/api/cloud/v2/accounts/%s", client.URL, accountID)
22+
}
23+
24+
func (client *sysdigSecureClient) CreateCloudAccount(ctx context.Context, cloudAccount *CloudAccount) (*CloudAccount, error) {
25+
response, err := client.doSysdigSecureRequest(ctx, http.MethodPost, client.cloudAccountURL(true), cloudAccount.ToJSON())
26+
if err != nil {
27+
return nil, err
28+
}
29+
defer response.Body.Close()
30+
31+
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
32+
err = errorFromResponse(response)
33+
return nil, err
34+
}
35+
36+
bodyBytes, _ := ioutil.ReadAll(response.Body)
37+
return CloudAccountFromJSON(bodyBytes), nil
38+
}
39+
40+
func (client *sysdigSecureClient) GetCloudAccountById(ctx context.Context, accountID string) (*CloudAccount, error) {
41+
response, err := client.doSysdigSecureRequest(ctx, http.MethodGet, client.cloudAccountByIdURL(accountID, true), nil)
42+
if err != nil {
43+
return nil, err
44+
}
45+
defer response.Body.Close()
46+
47+
if response.StatusCode != http.StatusOK {
48+
return nil, errorFromResponse(response)
49+
}
50+
51+
bodyBytes, err := ioutil.ReadAll(response.Body)
52+
if err != nil {
53+
return nil, err
54+
}
55+
56+
return CloudAccountFromJSON(bodyBytes), nil
57+
}
58+
59+
func (client *sysdigSecureClient) DeleteCloudAccount(ctx context.Context, accountID string) error {
60+
response, err := client.doSysdigSecureRequest(ctx, http.MethodDelete, client.cloudAccountByIdURL(accountID, false), nil)
61+
if err != nil {
62+
return err
63+
}
64+
defer response.Body.Close()
65+
66+
if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK {
67+
return errorFromResponse(response)
68+
}
69+
return nil
70+
}
71+
72+
func (client *sysdigSecureClient) UpdateCloudAccount(ctx context.Context, accountID string, cloudAccount *CloudAccount) (*CloudAccount, error) {
73+
response, err := client.doSysdigSecureRequest(ctx, http.MethodPut, client.cloudAccountByIdURL(accountID, true), cloudAccount.ToJSON())
74+
if err != nil {
75+
return nil, err
76+
}
77+
defer response.Body.Close()
78+
79+
if response.StatusCode != http.StatusOK {
80+
err = errorFromResponse(response)
81+
return nil, err
82+
}
83+
84+
bodyBytes, _ := ioutil.ReadAll(response.Body)
85+
return CloudAccountFromJSON(bodyBytes), nil
86+
}

sysdig/internal/client/secure/models.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,25 @@ func VulnerabilityExceptionFromJSON(body []byte) *VulnerabilityException {
360360

361361
return &result
362362
}
363+
364+
// -------- CloudAccount --------
365+
366+
type CloudAccount struct {
367+
AccountID string `json:"accountId"`
368+
Provider string `json:"provider"`
369+
Alias string `json:"alias"`
370+
RoleAvailable bool `json:"roleAvailable"`
371+
ExternalID string `json:"externalId,omitempty"`
372+
}
373+
374+
func (e *CloudAccount) ToJSON() io.Reader {
375+
payload, _ := json.Marshal(*e)
376+
return bytes.NewBuffer(payload)
377+
}
378+
379+
func CloudAccountFromJSON(body []byte) *CloudAccount {
380+
var result CloudAccount
381+
json.Unmarshal(body, &result)
382+
383+
return &result
384+
}

sysdig/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func Provider() *schema.Provider {
7070
"sysdig_secure_macro": resourceSysdigSecureMacro(),
7171
"sysdig_secure_vulnerability_exception": resourceSysdigSecureVulnerabilityException(),
7272
"sysdig_secure_vulnerability_exception_list": resourceSysdigSecureVulnerabilityExceptionList(),
73+
"sysdig_secure_cloud_account": resourceSysdigSecureCloudAccount(),
7374

7475
"sysdig_monitor_alert_downtime": resourceSysdigMonitorAlertDowntime(),
7576
"sysdig_monitor_alert_metric": resourceSysdigMonitorAlertMetric(),
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package sysdig
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/draios/terraform-provider-sysdig/sysdig/internal/client/secure"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
func resourceSysdigSecureCloudAccount() *schema.Resource {
13+
timeout := 5 * time.Minute
14+
15+
return &schema.Resource{
16+
CreateContext: resourceSysdigSecureCloudAccountCreate,
17+
UpdateContext: resourceSysdigSecureCloudAccountUpdate,
18+
ReadContext: resourceSysdigSecureCloudAccountRead,
19+
DeleteContext: resourceSysdigSecureCloudAccountDelete,
20+
Importer: &schema.ResourceImporter{
21+
StateContext: schema.ImportStatePassthroughContext,
22+
},
23+
24+
Timeouts: &schema.ResourceTimeout{
25+
Create: schema.DefaultTimeout(timeout),
26+
Update: schema.DefaultTimeout(timeout),
27+
Read: schema.DefaultTimeout(timeout),
28+
Delete: schema.DefaultTimeout(timeout),
29+
},
30+
Schema: map[string]*schema.Schema{
31+
"account_id": {
32+
Type: schema.TypeString,
33+
Required: true,
34+
},
35+
"cloud_provider": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
},
39+
"alias": {
40+
Type: schema.TypeString,
41+
Optional: true,
42+
},
43+
"role_enabled": {
44+
Type: schema.TypeBool,
45+
Optional: true,
46+
Default: false,
47+
},
48+
"external_id": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
},
53+
}
54+
}
55+
56+
func resourceSysdigSecureCloudAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
57+
client, err := meta.(SysdigClients).sysdigSecureClient()
58+
if err != nil {
59+
return diag.FromErr(err)
60+
}
61+
62+
cloudAccount, err := client.CreateCloudAccount(ctx, cloudAccountFromResourceData(d))
63+
if err != nil {
64+
return diag.FromErr(err)
65+
}
66+
67+
d.SetId(cloudAccount.AccountID)
68+
d.Set("account_id", cloudAccount.AccountID)
69+
d.Set("cloud_provider", cloudAccount.Provider)
70+
d.Set("alias", cloudAccount.Alias)
71+
d.Set("role_enabled", cloudAccount.RoleAvailable)
72+
d.Set("external_id", cloudAccount.ExternalID)
73+
74+
return nil
75+
}
76+
77+
func resourceSysdigSecureCloudAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
78+
client, err := meta.(SysdigClients).sysdigSecureClient()
79+
if err != nil {
80+
d.SetId("")
81+
return diag.FromErr(err)
82+
}
83+
84+
cloudAccount, err := client.GetCloudAccountById(ctx, d.Id())
85+
if err != nil {
86+
d.SetId("")
87+
return diag.FromErr(err)
88+
}
89+
90+
d.Set("account_id", cloudAccount.AccountID)
91+
d.Set("cloud_provider", cloudAccount.Provider)
92+
d.Set("alias", cloudAccount.Alias)
93+
d.Set("role_enabled", cloudAccount.RoleAvailable)
94+
d.Set("external_id", cloudAccount.ExternalID)
95+
96+
return nil
97+
}
98+
99+
func resourceSysdigSecureCloudAccountUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
100+
client, err := meta.(SysdigClients).sysdigSecureClient()
101+
if err != nil {
102+
return diag.FromErr(err)
103+
}
104+
105+
_, err = client.UpdateCloudAccount(ctx, d.Id(), cloudAccountFromResourceData(d))
106+
if err != nil {
107+
return diag.FromErr(err)
108+
}
109+
110+
return nil
111+
}
112+
113+
func resourceSysdigSecureCloudAccountDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
114+
client, err := meta.(SysdigClients).sysdigSecureClient()
115+
if err != nil {
116+
return diag.FromErr(err)
117+
}
118+
119+
err = client.DeleteCloudAccount(ctx, d.Id())
120+
if err != nil {
121+
return diag.FromErr(err)
122+
}
123+
return nil
124+
}
125+
126+
func cloudAccountFromResourceData(d *schema.ResourceData) *secure.CloudAccount {
127+
return &secure.CloudAccount{
128+
AccountID: d.Get("account_id").(string),
129+
Provider: d.Get("cloud_provider").(string),
130+
Alias: d.Get("alias").(string),
131+
RoleAvailable: d.Get("role_enabled").(bool),
132+
}
133+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package sysdig_test
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
12+
"github.com/draios/terraform-provider-sysdig/sysdig"
13+
)
14+
15+
func TestAccSecureCloudAccount(t *testing.T) {
16+
rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) }
17+
accID := rText()
18+
resource.ParallelTest(t, resource.TestCase{
19+
PreCheck: func() {
20+
if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" {
21+
t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests")
22+
}
23+
},
24+
ProviderFactories: map[string]func() (*schema.Provider, error){
25+
"sysdig": func() (*schema.Provider, error) {
26+
return sysdig.Provider(), nil
27+
},
28+
},
29+
Steps: []resource.TestStep{
30+
{
31+
Config: secureCloudAccountWithID(accID),
32+
},
33+
{
34+
Config: secureCloudAccountMinimumConfiguration(accID),
35+
},
36+
{
37+
ResourceName: "sysdig_secure_cloud_account.sample",
38+
ImportState: true,
39+
ImportStateVerify: true,
40+
},
41+
},
42+
})
43+
}
44+
45+
func secureCloudAccountWithID(accountID string) string {
46+
return fmt.Sprintf(`
47+
resource "sysdig_secure_cloud_account" "sample" {
48+
account_id = "sample-%s"
49+
cloud_provider = "aws"
50+
alias = "%s"
51+
role_enabled = "false"
52+
}
53+
`, accountID, accountID)
54+
}
55+
56+
func secureCloudAccountMinimumConfiguration(accountID string) string {
57+
return fmt.Sprintf(`
58+
resource "sysdig_secure_cloud_account" "sample" {
59+
account_id = "sample-%s"
60+
cloud_provider = "aws"
61+
}`, accountID)
62+
}

0 commit comments

Comments
 (0)