Skip to content

Commit 4474c76

Browse files
authored
feat(iam): add iam application (#1339)
1 parent b09d131 commit 4474c76

11 files changed

+1018
-1
lines changed

.github/workflows/acceptance-tests.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
- Container
1616
- Domain
1717
- Function
18+
- Iam
1819
- Instance
1920
- Iot
2021
- K8S
@@ -45,3 +46,4 @@ jobs:
4546
SCW_DEBUG: 0
4647
SCW_ACCESS_KEY: "SCWXXXXXXXXXXXXXFAKE"
4748
SCW_SECRET_KEY: "11111111-1111-1111-1111-111111111111"
49+
SCW_ENABLE_BETA: true

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/hashicorp/go-retryablehttp v0.7.1
1212
github.com/hashicorp/terraform-plugin-log v0.4.0
1313
github.com/hashicorp/terraform-plugin-sdk/v2 v2.17.0
14-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220616135310-b11a2a9a6c76
14+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f
1515
github.com/stretchr/testify v1.7.1
1616
)
1717

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
252252
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
253253
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220616135310-b11a2a9a6c76 h1:FjeyXcr7eAD4GkstU4ZrpM+GJq8t0zo5h1BwknvJKB8=
254254
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220616135310-b11a2a9a6c76/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
255+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f h1:wLBnkc5V6oq/u9ep7FIpUHzl2vgaURY+Dr2Mp/7Rv/c=
256+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
255257
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
256258
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
257259
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=

scaleway/helpers_iam.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package scaleway
2+
3+
import iam "github.com/scaleway/scaleway-sdk-go/api/iam/v1alpha1"
4+
5+
// instanceAPIWithZone returns a new iam API for a Create request
6+
func iamAPI(m interface{}) *iam.API {
7+
meta := m.(*Meta)
8+
return iam.NewAPI(meta.scwClient)
9+
}

scaleway/provider.go

+21
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7+
"os"
78

89
"github.com/hashicorp/terraform-plugin-log/tflog"
910
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -12,6 +13,8 @@ import (
1213
"github.com/scaleway/scaleway-sdk-go/scw"
1314
)
1415

16+
var terraformBetaEnabled = os.Getenv(scw.ScwEnableBeta) != ""
17+
1518
// ProviderConfig config can be used to provide additional config when creating provider.
1619
type ProviderConfig struct {
1720
// Meta can be used to override Meta that will be used by the provider.
@@ -24,6 +27,22 @@ func DefaultProviderConfig() *ProviderConfig {
2427
return &ProviderConfig{}
2528
}
2629

30+
func addBetaResources(provider *schema.Provider) {
31+
if !terraformBetaEnabled {
32+
return
33+
}
34+
betaResources := map[string]*schema.Resource{
35+
"scaleway_iam_application": resourceScalewayIamApplication(),
36+
}
37+
betaDataSources := map[string]*schema.Resource{}
38+
for resourceName, resource := range betaResources {
39+
provider.ResourcesMap[resourceName] = resource
40+
}
41+
for resourceName, resource := range betaDataSources {
42+
provider.DataSourcesMap[resourceName] = resource
43+
}
44+
}
45+
2746
// Provider returns a terraform.ResourceProvider.
2847
func Provider(config *ProviderConfig) plugin.ProviderFunc {
2948
return func() *schema.Provider {
@@ -151,6 +170,8 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
151170
},
152171
}
153172

173+
addBetaResources(p)
174+
154175
p.ConfigureContextFunc = func(ctx context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) {
155176
terraformVersion := p.TerraformVersion
156177

scaleway/provider_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ func NewTestTools(t *testing.T) *TestTools {
118118
}
119119
}
120120

121+
func SkipBetaTest(t *testing.T) {
122+
t.Helper()
123+
if !terraformBetaEnabled {
124+
t.Skip("Skip test as beta is not enabled")
125+
}
126+
}
127+
121128
func TestAccScalewayProvider_SSHKeys(t *testing.T) {
122129
tt := NewTestTools(t)
123130
defer tt.Cleanup()

scaleway/resource_iam_application.go

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
iam "github.com/scaleway/scaleway-sdk-go/api/iam/v1alpha1"
9+
"github.com/scaleway/scaleway-sdk-go/scw"
10+
)
11+
12+
func resourceScalewayIamApplication() *schema.Resource {
13+
return &schema.Resource{
14+
CreateContext: resourceScalewayIamApplicationCreate,
15+
ReadContext: resourceScalewayIamApplicationRead,
16+
UpdateContext: resourceScalewayIamApplicationUpdate,
17+
DeleteContext: resourceScalewayIamApplicationDelete,
18+
Importer: &schema.ResourceImporter{
19+
StateContext: schema.ImportStatePassthroughContext,
20+
},
21+
SchemaVersion: 0,
22+
Schema: map[string]*schema.Schema{
23+
"name": {
24+
Type: schema.TypeString,
25+
Computed: true,
26+
Optional: true,
27+
Description: "The name of the iam application",
28+
},
29+
"description": {
30+
Type: schema.TypeString,
31+
Optional: true,
32+
Description: "The description of the iam application",
33+
},
34+
"created_at": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
Description: "The date and time of the creation of the application",
38+
},
39+
"updated_at": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
Description: "The date and time of the last update of the application",
43+
},
44+
"editable": {
45+
Type: schema.TypeBool,
46+
Computed: true,
47+
Description: "Whether or not the application is editable.",
48+
},
49+
"organization_id": organizationIDSchema(),
50+
},
51+
}
52+
}
53+
54+
func resourceScalewayIamApplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
55+
api := iamAPI(meta)
56+
app, err := api.CreateApplication(&iam.CreateApplicationRequest{
57+
Name: expandOrGenerateString(d.Get("name"), "application-"),
58+
Description: d.Get("description").(string),
59+
}, scw.WithContext(ctx))
60+
if err != nil {
61+
return diag.FromErr(err)
62+
}
63+
64+
d.SetId(app.ID)
65+
66+
return resourceScalewayIamApplicationRead(ctx, d, meta)
67+
}
68+
69+
func resourceScalewayIamApplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
70+
api := iamAPI(meta)
71+
app, err := api.GetApplication(&iam.GetApplicationRequest{
72+
ApplicationID: d.Id(),
73+
}, scw.WithContext(ctx))
74+
if err != nil {
75+
if is404Error(err) {
76+
d.SetId("")
77+
return nil
78+
}
79+
return diag.FromErr(err)
80+
}
81+
_ = d.Set("name", app.Name)
82+
_ = d.Set("description", app.Description)
83+
_ = d.Set("created_at", flattenTime(app.CreatedAt))
84+
_ = d.Set("updated_at", flattenTime(app.UpdatedAt))
85+
_ = d.Set("organization_id", app.OrganizationID)
86+
_ = d.Set("editable", app.Editable)
87+
88+
return nil
89+
}
90+
91+
func resourceScalewayIamApplicationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
92+
api := iamAPI(meta)
93+
94+
req := &iam.UpdateApplicationRequest{
95+
ApplicationID: d.Id(),
96+
}
97+
98+
hasChanged := false
99+
100+
if d.HasChange("name") {
101+
req.Name = expandStringPtr(d.Get("name"))
102+
hasChanged = true
103+
}
104+
if d.HasChange("description") {
105+
req.Description = expandStringPtr(d.Get("description"))
106+
hasChanged = true
107+
}
108+
109+
if hasChanged {
110+
_, err := api.UpdateApplication(req, scw.WithContext(ctx))
111+
if err != nil {
112+
return diag.FromErr(err)
113+
}
114+
}
115+
116+
return resourceScalewayIamApplicationRead(ctx, d, meta)
117+
}
118+
119+
func resourceScalewayIamApplicationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
120+
api := iamAPI(meta)
121+
122+
err := api.DeleteApplication(&iam.DeleteApplicationRequest{
123+
ApplicationID: d.Id(),
124+
}, scw.WithContext(ctx))
125+
if err != nil && !is404Error(err) {
126+
return diag.FromErr(err)
127+
}
128+
129+
return nil
130+
}
+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9+
iam "github.com/scaleway/scaleway-sdk-go/api/iam/v1alpha1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
)
12+
13+
func init() {
14+
resource.AddTestSweepers("scaleway_iam_application", &resource.Sweeper{
15+
Name: "scaleway_iam_application",
16+
F: testSweepIamApplication,
17+
})
18+
}
19+
20+
func testSweepIamApplication(_ string) error {
21+
return sweep(func(scwClient *scw.Client) error {
22+
api := iam.NewAPI(scwClient)
23+
24+
listApps, err := api.ListApplications(&iam.ListApplicationsRequest{})
25+
if err != nil {
26+
return fmt.Errorf("failed to list applications: %w", err)
27+
}
28+
for _, app := range listApps.Applications {
29+
err = api.DeleteApplication(&iam.DeleteApplicationRequest{
30+
ApplicationID: app.ID,
31+
})
32+
if err != nil {
33+
return fmt.Errorf("failed to delete application: %w", err)
34+
}
35+
}
36+
return nil
37+
})
38+
}
39+
40+
func TestAccScalewayIamApplication_Basic(t *testing.T) {
41+
SkipBetaTest(t)
42+
tt := NewTestTools(t)
43+
defer tt.Cleanup()
44+
resource.ParallelTest(t, resource.TestCase{
45+
ProviderFactories: tt.ProviderFactories,
46+
CheckDestroy: testAccCheckScalewayIamApplicationDestroy(tt),
47+
Steps: []resource.TestStep{
48+
{
49+
Config: `
50+
resource "scaleway_iam_application" "main" {
51+
name = "tf_tests_app_basic"
52+
description = "a description"
53+
}
54+
`,
55+
Check: resource.ComposeTestCheckFunc(
56+
testAccCheckScalewayIamApplicationExists(tt, "scaleway_iam_application.main"),
57+
resource.TestCheckResourceAttr("scaleway_iam_application.main", "name", "tf_tests_app_basic"),
58+
resource.TestCheckResourceAttr("scaleway_iam_application.main", "description", "a description"),
59+
),
60+
},
61+
{
62+
Config: `
63+
resource "scaleway_iam_application" "main" {
64+
name = "tf_tests_app_basic_rename"
65+
description = "another description"
66+
}
67+
`,
68+
Check: resource.ComposeTestCheckFunc(
69+
testAccCheckScalewayIamApplicationExists(tt, "scaleway_iam_application.main"),
70+
resource.TestCheckResourceAttr("scaleway_iam_application.main", "name", "tf_tests_app_basic_rename"),
71+
resource.TestCheckResourceAttr("scaleway_iam_application.main", "description", "another description"),
72+
),
73+
},
74+
},
75+
})
76+
}
77+
78+
func TestAccScalewayIamApplication_NoUpdate(t *testing.T) {
79+
SkipBetaTest(t)
80+
tt := NewTestTools(t)
81+
defer tt.Cleanup()
82+
83+
resource.ParallelTest(t, resource.TestCase{
84+
ProviderFactories: tt.ProviderFactories,
85+
CheckDestroy: testAccCheckScalewayIamApplicationDestroy(tt),
86+
Steps: []resource.TestStep{
87+
{
88+
Config: `
89+
resource "scaleway_iam_application" "main" {
90+
name = "tf_tests_app_noupdate"
91+
}
92+
`,
93+
Check: resource.ComposeTestCheckFunc(
94+
testAccCheckScalewayIamApplicationExists(tt, "scaleway_iam_application.main"),
95+
),
96+
},
97+
{
98+
Config: `
99+
resource "scaleway_iam_application" "main" {
100+
name = "tf_tests_app_noupdate"
101+
}
102+
`,
103+
Check: resource.ComposeTestCheckFunc(
104+
testAccCheckScalewayIamApplicationExists(tt, "scaleway_iam_application.main"),
105+
),
106+
},
107+
},
108+
})
109+
}
110+
111+
func testAccCheckScalewayIamApplicationExists(tt *TestTools, name string) resource.TestCheckFunc {
112+
return func(s *terraform.State) error {
113+
rs, ok := s.RootModule().Resources[name]
114+
if !ok {
115+
return fmt.Errorf("resource not found: %s", name)
116+
}
117+
118+
iamAPI := iamAPI(tt.Meta)
119+
120+
_, err := iamAPI.GetApplication(&iam.GetApplicationRequest{
121+
ApplicationID: rs.Primary.ID,
122+
})
123+
if err != nil {
124+
return fmt.Errorf("could not find application: %w", err)
125+
}
126+
127+
return nil
128+
}
129+
}
130+
131+
func testAccCheckScalewayIamApplicationDestroy(tt *TestTools) resource.TestCheckFunc {
132+
return func(s *terraform.State) error {
133+
for _, rs := range s.RootModule().Resources {
134+
if rs.Type != "scaleway_iam_application" {
135+
continue
136+
}
137+
138+
iamAPI := iamAPI(tt.Meta)
139+
140+
_, err := iamAPI.GetApplication(&iam.GetApplicationRequest{
141+
ApplicationID: rs.Primary.ID,
142+
})
143+
144+
// If no error resource still exist
145+
if err == nil {
146+
return fmt.Errorf("resource %s(%s) still exist", rs.Type, rs.Primary.ID)
147+
}
148+
149+
// Unexpected api error we return it
150+
if !is404Error(err) {
151+
return err
152+
}
153+
}
154+
155+
return nil
156+
}
157+
}

0 commit comments

Comments
 (0)