• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Scalr / terraform-provider-scalr / 16519773832

25 Jul 2025 10:26AM UTC coverage: 63.857%. First build
16519773832

Pull #441

github

DayS1eeper
SCALRCORE-35309
Pull Request #441: SCALRCORE-35309 Provider > Namespaces support.

242 of 444 new or added lines in 6 files covered. (54.5%)

8749 of 13701 relevant lines covered (63.86%)

301.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.56
/internal/provider/module_namespace_resource.go
1
package provider
2

3
import (
4
        "context"
5
        "errors"
6

7
        "github.com/hashicorp/terraform-plugin-framework/path"
8
        "github.com/hashicorp/terraform-plugin-framework/resource"
9
        "github.com/hashicorp/terraform-plugin-framework/resource/schema"
10
        "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
11
        "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
12
        "github.com/hashicorp/terraform-plugin-framework/schema/validator"
13
        "github.com/hashicorp/terraform-plugin-framework/types"
14
        "github.com/scalr/go-scalr"
15

16
        "github.com/scalr/terraform-provider-scalr/internal/framework"
17
        "github.com/scalr/terraform-provider-scalr/internal/framework/validation"
18
)
19

20
var (
21
        _ resource.Resource                     = &moduleNamespaceResource{}
22
        _ resource.ResourceWithConfigure        = &moduleNamespaceResource{}
23
        _ resource.ResourceWithConfigValidators = &moduleNamespaceResource{}
24
        _ resource.ResourceWithImportState      = &moduleNamespaceResource{}
25
)
26

27
func newModuleNamespaceResource() resource.Resource {
1,925✔
28
        return &moduleNamespaceResource{}
1,925✔
29
}
1,925✔
30

31
type moduleNamespaceResource struct {
32
        framework.ResourceWithScalrClient
33
}
34

35
type moduleNamespaceResourceModel struct {
36
        ID           types.String `tfsdk:"id"`
37
        Name         types.String `tfsdk:"name"`
38
        IsShared     types.Bool   `tfsdk:"is_shared"`
39
        Environments types.Set    `tfsdk:"environments"`
40
        Owners       types.Set    `tfsdk:"owners"`
41
}
42

43
func (r *moduleNamespaceResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
175✔
44
        resp.TypeName = req.ProviderTypeName + "_module_namespace"
175✔
45
}
175✔
46

47
func (r *moduleNamespaceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
1,619✔
48
        resp.Schema = schema.Schema{
1,619✔
49
                MarkdownDescription: "Manages the state of module namespaces in Scalr.",
1,619✔
50

1,619✔
51
                Attributes: map[string]schema.Attribute{
1,619✔
52
                        "id": schema.StringAttribute{
1,619✔
53
                                MarkdownDescription: "The ID of this resource.",
1,619✔
54
                                Computed:            true,
1,619✔
55
                                PlanModifiers: []planmodifier.String{
1,619✔
56
                                        stringplanmodifier.UseStateForUnknown(),
1,619✔
57
                                },
1,619✔
58
                        },
1,619✔
59
                        "name": schema.StringAttribute{
1,619✔
60
                                MarkdownDescription: "Name of the module namespace.",
1,619✔
61
                                Required:            true,
1,619✔
62
                                PlanModifiers: []planmodifier.String{
1,619✔
63
                                        stringplanmodifier.RequiresReplace(),
1,619✔
64
                                },
1,619✔
65
                                Validators: []validator.String{
1,619✔
66
                                        validation.StringIsNotWhiteSpace(),
1,619✔
67
                                        validation.StringIsNamespaceName(),
1,619✔
68
                                },
1,619✔
69
                        },
1,619✔
70
                        "is_shared": schema.BoolAttribute{
1,619✔
71
                                MarkdownDescription: "Whether the module namespace is shared.",
1,619✔
72
                                Optional:            true,
1,619✔
73
                                Computed:            true,
1,619✔
74
                        },
1,619✔
75
                        "environments": schema.SetAttribute{
1,619✔
76
                                ElementType:         types.StringType,
1,619✔
77
                                Optional:            true,
1,619✔
78
                                MarkdownDescription: "Set of environment IDs associated with the module namespace.",
1,619✔
79
                        },
1,619✔
80
                        "owners": schema.SetAttribute{
1,619✔
81
                                ElementType:         types.StringType,
1,619✔
82
                                Optional:            true,
1,619✔
83
                                MarkdownDescription: "Set of team IDs that own the module namespace.",
1,619✔
84
                        },
1,619✔
85
                },
1,619✔
86
        }
1,619✔
87
}
1,619✔
88

89
func (r *moduleNamespaceResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
52✔
90
        return []resource.ConfigValidator{}
52✔
91
}
52✔
92

93
func (r *moduleNamespaceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
5✔
94
        var plan moduleNamespaceResourceModel
5✔
95

5✔
96
        resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
5✔
97
        if resp.Diagnostics.HasError() {
5✔
NEW
98
                return
×
NEW
99
        }
×
100

101
        var environments []string
5✔
102
        resp.Diagnostics.Append(plan.Environments.ElementsAs(ctx, &environments, false)...)
5✔
103
        if resp.Diagnostics.HasError() {
5✔
NEW
104
                return
×
NEW
105
        }
×
106

107
        var owners []string
5✔
108
        resp.Diagnostics.Append(plan.Owners.ElementsAs(ctx, &owners, false)...)
5✔
109
        if resp.Diagnostics.HasError() {
5✔
NEW
110
                return
×
NEW
111
        }
×
112

113
        // Convert environment IDs to Environment objects
114
        var environmentObjects []*scalr.Environment
5✔
115
        for _, envID := range environments {
5✔
NEW
116
                environmentObjects = append(environmentObjects, &scalr.Environment{ID: envID})
×
NEW
117
        }
×
118

119
        // Convert owner IDs to Team objects
120
        var ownerObjects []*scalr.Team
5✔
121
        for _, ownerID := range owners {
5✔
NEW
122
                ownerObjects = append(ownerObjects, &scalr.Team{ID: ownerID})
×
NEW
123
        }
×
124

125
        opts := scalr.ModuleNamespaceCreateOptions{
5✔
126
                Name:         plan.Name.ValueStringPointer(),
5✔
127
                IsShared:     plan.IsShared.ValueBoolPointer(),
5✔
128
                Environments: environmentObjects,
5✔
129
                Owners:       ownerObjects,
5✔
130
        }
5✔
131

5✔
132
        namespace, err := r.Client.ModuleNamespaces.Create(ctx, opts)
5✔
133
        if err != nil {
5✔
NEW
134
                resp.Diagnostics.AddError("Error creating module namespace", err.Error())
×
NEW
135
                return
×
NEW
136
        }
×
137

138
        plan.ID = types.StringValue(namespace.ID)
5✔
139
        plan.Name = types.StringValue(namespace.Name)
5✔
140
        plan.IsShared = types.BoolValue(namespace.IsShared)
5✔
141

5✔
142
        // Set environments
5✔
143
        if len(namespace.Environments) > 0 {
5✔
NEW
144
                environmentIDs := make([]string, len(namespace.Environments))
×
NEW
145
                for i, env := range namespace.Environments {
×
NEW
146
                        environmentIDs[i] = env.ID
×
NEW
147
                }
×
NEW
148
                environmentsSet, diags := types.SetValueFrom(ctx, types.StringType, environmentIDs)
×
NEW
149
                resp.Diagnostics.Append(diags...)
×
NEW
150
                if resp.Diagnostics.HasError() {
×
NEW
151
                        return
×
NEW
152
                }
×
NEW
153
                plan.Environments = environmentsSet
×
154
        } else {
5✔
155
                plan.Environments = types.SetNull(types.StringType)
5✔
156
        }
5✔
157

158
        // Set owners
159
        if len(namespace.Owners) > 0 {
5✔
NEW
160
                ownerIDs := make([]string, len(namespace.Owners))
×
NEW
161
                for i, owner := range namespace.Owners {
×
NEW
162
                        ownerIDs[i] = owner.ID
×
NEW
163
                }
×
NEW
164
                ownersSet, diags := types.SetValueFrom(ctx, types.StringType, ownerIDs)
×
NEW
165
                resp.Diagnostics.Append(diags...)
×
NEW
166
                if resp.Diagnostics.HasError() {
×
NEW
167
                        return
×
NEW
168
                }
×
NEW
169
                plan.Owners = ownersSet
×
170
        } else {
5✔
171
                plan.Owners = types.SetNull(types.StringType)
5✔
172
        }
5✔
173

174
        resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
5✔
175
        if resp.Diagnostics.HasError() {
5✔
NEW
176
                return
×
NEW
177
        }
×
178
}
179

180
func (r *moduleNamespaceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
11✔
181
        var state moduleNamespaceResourceModel
11✔
182
        resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
11✔
183
        if resp.Diagnostics.HasError() {
11✔
NEW
184
                return
×
NEW
185
        }
×
186

187
        namespace, err := r.Client.ModuleNamespaces.Read(ctx, state.ID.ValueString())
11✔
188
        if err != nil {
11✔
NEW
189
                if errors.Is(err, scalr.ErrResourceNotFound) {
×
NEW
190
                        resp.State.RemoveResource(ctx)
×
NEW
191
                        return
×
NEW
192
                }
×
NEW
193
                resp.Diagnostics.AddError("Error retrieving module namespace", err.Error())
×
NEW
194
                return
×
195
        }
196

197
        state.Name = types.StringValue(namespace.Name)
11✔
198
        state.IsShared = types.BoolValue(namespace.IsShared)
11✔
199

11✔
200
        // Set environments
11✔
201
        if len(namespace.Environments) > 0 {
11✔
NEW
202
                environmentIDs := make([]string, len(namespace.Environments))
×
NEW
203
                for i, env := range namespace.Environments {
×
NEW
204
                        environmentIDs[i] = env.ID
×
NEW
205
                }
×
NEW
206
                environmentsSet, diags := types.SetValueFrom(ctx, types.StringType, environmentIDs)
×
NEW
207
                resp.Diagnostics.Append(diags...)
×
NEW
208
                if resp.Diagnostics.HasError() {
×
NEW
209
                        return
×
NEW
210
                }
×
NEW
211
                state.Environments = environmentsSet
×
212
        } else {
11✔
213
                state.Environments = types.SetNull(types.StringType)
11✔
214
        }
11✔
215

216
        // Set owners
217
        if len(namespace.Owners) > 0 {
11✔
NEW
218
                ownerIDs := make([]string, len(namespace.Owners))
×
NEW
219
                for i, owner := range namespace.Owners {
×
NEW
220
                        ownerIDs[i] = owner.ID
×
NEW
221
                }
×
NEW
222
                ownersSet, diags := types.SetValueFrom(ctx, types.StringType, ownerIDs)
×
NEW
223
                resp.Diagnostics.Append(diags...)
×
NEW
224
                if resp.Diagnostics.HasError() {
×
NEW
225
                        return
×
NEW
226
                }
×
NEW
227
                state.Owners = ownersSet
×
228
        } else {
11✔
229
                state.Owners = types.SetNull(types.StringType)
11✔
230
        }
11✔
231

232
        resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
11✔
233
        if resp.Diagnostics.HasError() {
11✔
NEW
234
                return
×
NEW
235
        }
×
236
}
237

NEW
238
func (r *moduleNamespaceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
×
NEW
239
        var plan moduleNamespaceResourceModel
×
NEW
240
        resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
×
NEW
241
        if resp.Diagnostics.HasError() {
×
NEW
242
                return
×
NEW
243
        }
×
244

NEW
245
        var environments []string
×
NEW
246
        resp.Diagnostics.Append(plan.Environments.ElementsAs(ctx, &environments, false)...)
×
NEW
247
        if resp.Diagnostics.HasError() {
×
NEW
248
                return
×
NEW
249
        }
×
250

NEW
251
        var owners []string
×
NEW
252
        resp.Diagnostics.Append(plan.Owners.ElementsAs(ctx, &owners, false)...)
×
NEW
253
        if resp.Diagnostics.HasError() {
×
NEW
254
                return
×
NEW
255
        }
×
256

257
        // Convert environment IDs to Environment objects
NEW
258
        var environmentObjects []*scalr.Environment
×
NEW
259
        for _, envID := range environments {
×
NEW
260
                environmentObjects = append(environmentObjects, &scalr.Environment{ID: envID})
×
NEW
261
        }
×
262

263
        // Convert owner IDs to Team objects
NEW
264
        var ownerObjects []*scalr.Team
×
NEW
265
        for _, ownerID := range owners {
×
NEW
266
                ownerObjects = append(ownerObjects, &scalr.Team{ID: ownerID})
×
NEW
267
        }
×
268

NEW
269
        opts := scalr.ModuleNamespaceUpdateOptions{
×
NEW
270
                IsShared:     plan.IsShared.ValueBoolPointer(),
×
NEW
271
                Environments: environmentObjects,
×
NEW
272
                Owners:       ownerObjects,
×
NEW
273
        }
×
NEW
274

×
NEW
275
        namespace, err := r.Client.ModuleNamespaces.Update(ctx, plan.ID.ValueString(), opts)
×
NEW
276
        if err != nil {
×
NEW
277
                resp.Diagnostics.AddError("Error updating module namespace", err.Error())
×
NEW
278
                return
×
NEW
279
        }
×
280

NEW
281
        plan.Name = types.StringValue(namespace.Name)
×
NEW
282
        plan.IsShared = types.BoolValue(namespace.IsShared)
×
NEW
283

×
NEW
284
        // Set environments
×
NEW
285
        if len(namespace.Environments) > 0 {
×
NEW
286
                environmentIDs := make([]string, len(namespace.Environments))
×
NEW
287
                for i, env := range namespace.Environments {
×
NEW
288
                        environmentIDs[i] = env.ID
×
NEW
289
                }
×
NEW
290
                environmentsSet, diags := types.SetValueFrom(ctx, types.StringType, environmentIDs)
×
NEW
291
                resp.Diagnostics.Append(diags...)
×
NEW
292
                if resp.Diagnostics.HasError() {
×
NEW
293
                        return
×
NEW
294
                }
×
NEW
295
                plan.Environments = environmentsSet
×
NEW
296
        } else {
×
NEW
297
                plan.Environments = types.SetNull(types.StringType)
×
NEW
298
        }
×
299

300
        // Set owners
NEW
301
        if len(namespace.Owners) > 0 {
×
NEW
302
                ownerIDs := make([]string, len(namespace.Owners))
×
NEW
303
                for i, owner := range namespace.Owners {
×
NEW
304
                        ownerIDs[i] = owner.ID
×
NEW
305
                }
×
NEW
306
                ownersSet, diags := types.SetValueFrom(ctx, types.StringType, ownerIDs)
×
NEW
307
                resp.Diagnostics.Append(diags...)
×
NEW
308
                if resp.Diagnostics.HasError() {
×
NEW
309
                        return
×
NEW
310
                }
×
NEW
311
                plan.Owners = ownersSet
×
NEW
312
        } else {
×
NEW
313
                plan.Owners = types.SetNull(types.StringType)
×
NEW
314
        }
×
315

NEW
316
        resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
×
NEW
317
        if resp.Diagnostics.HasError() {
×
NEW
318
                return
×
NEW
319
        }
×
320
}
321

322
func (r *moduleNamespaceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
5✔
323
        var state moduleNamespaceResourceModel
5✔
324
        resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
5✔
325
        if resp.Diagnostics.HasError() {
5✔
NEW
326
                return
×
NEW
327
        }
×
328

329
        err := r.Client.ModuleNamespaces.Delete(ctx, state.ID.ValueString())
5✔
330
        if err != nil && !errors.Is(err, scalr.ErrResourceNotFound) {
5✔
NEW
331
                resp.Diagnostics.AddError("Error deleting module namespace", err.Error())
×
NEW
332
                return
×
NEW
333
        }
×
334
}
335

336
func (r *moduleNamespaceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
1✔
337
        resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
1✔
338
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc