Skip to content

Commit f9f7bf3

Browse files
Antoine Belluardremyleone
authored andcommitted
feat(container/serverless): add scaling_option block
1 parent 4110e51 commit f9f7bf3

File tree

8 files changed

+4742
-0
lines changed

8 files changed

+4742
-0
lines changed

docs/data-sources/container.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,20 @@ In addition to all arguments above, the following attributes are exported:
9393

9494
- `sandbox` - Execution environment of the container.
9595

96+
<<<<<<< HEAD
9697
- `heath_check` - Health check configuration block of the container.
9798
- `http` - HTTP health check configuration.
9899
- `path` - Path to use for the HTTP health check.
99100
- `failure_threshold` - Number of consecutive health check failures before considering the container unhealthy.
100101
- `interval`- Period between health checks (in seconds).
102+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
103+
- `sandbox` - (Optional) Execution environment of the container.
104+
=======
105+
- `scaling_option` - Configuration block used to decide when to scale up or down. Possible values:
106+
- `concurrent_requests_threshold` - Scale depending on the number of concurrent requests being processed per container instance.
107+
- `cpu_usage_threshold` - Scale depending on the CPU usage of a container instance.
108+
- `memory_usage_threshold`- Scale depending on the memory usage of a container instance.
109+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
101110
102111
- `status` - The container status.
103112

docs/resources/container.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,19 @@ The following arguments are supported:
8484

8585
- `sandbox` - (Optional) Execution environment of the container.
8686

87+
<<<<<<< HEAD
8788
- `heath_check` - (Optional) Health check configuration block of the container.
8889
- `http` - HTTP health check configuration.
8990
- `path` - Path to use for the HTTP health check.
9091
- `failure_threshold` - Number of consecutive health check failures before considering the container unhealthy.
9192
- `interval`- Period between health checks (in seconds).
93+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
94+
=======
95+
- `scaling_option` - (Optional) Configuration block used to decide when to scale up or down. Possible values:
96+
- `concurrent_requests_threshold` - Scale depending on the number of concurrent requests being processed per container instance.
97+
- `cpu_usage_threshold` - Scale depending on the CPU usage of a container instance.
98+
- `memory_usage_threshold`- Scale depending on the memory usage of a container instance.
99+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
92100
93101
- `port` - (Optional) The port to expose the container.
94102

@@ -160,6 +168,7 @@ The `memory_limit` (in MB) must correspond with the right amount of vCPU. Refer
160168
~>**Important:** Make sure to select the right resources, as you will be billed based on compute usage over time and the number of Containers executions.
161169
Refer to the [Serverless Containers pricing](https://www.scaleway.com/en/docs/faq/serverless-containers/#prices) for more information.
162170

171+
<<<<<<< HEAD
163172
## Health check configuration
164173

165174
Custom health checks can be configured on the container.
@@ -188,4 +197,27 @@ resource scaleway_container main {
188197

189198
~>**Important:** Another probe type can be set to TCP with the API, but currently the SDK has not been updated with this parameter.
190199
This is why the only probe that can be used here is the HTTP probe.
200+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
201+
Refer to the [Serverless Containers pricing](https://www.scaleway.com/en/docs/faq/serverless-containers/#prices) for more information.
202+
=======
203+
## Scaling option configuration
204+
205+
Scaling option block configuration allows you to choose which parameter will scale up/down containers. Options are number of concurrent requests, CPU or memory usage.
206+
It replaces current `max_concurrency` that has been deprecated.
207+
208+
Example:
209+
210+
```terraform
211+
resource scaleway_container main {
212+
name = "my-container-02"
213+
namespace_id = scaleway_container_namespace.main.id
214+
215+
scaling_option {
216+
concurrent_requests_threshold = 15
217+
}
218+
}
219+
```
220+
221+
~>**Important**: A maximum of one of these parameters may be set. Also, when `cpu_usage_threshold` or `memory_usage_threshold` are used, `min_scale` can't be set to 0.
222+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
191223
Refer to the [API Reference](https://www.scaleway.com/en/developers/api/serverless-containers/#path-containers-create-a-new-container) for more information.

internal/services/container/container.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ func ResourceContainer() *schema.Resource {
130130
Type: schema.TypeInt,
131131
Optional: true,
132132
Computed: true,
133+
Deprecated: "Use scaling_option.concurrent_requests_threshold instead. This attribute will be removed.",
133134
Description: "The maximum the number of simultaneous requests your container can handle at the same time.",
134135
ValidateFunc: validation.IntAtMost(containerMaxConcurrencyLimit),
135136
},
@@ -171,6 +172,7 @@ func ResourceContainer() *schema.Resource {
171172
Description: "Execution environment of the container.",
172173
ValidateDiagFunc: verify.ValidateEnum[container.ContainerSandbox](),
173174
},
175+
<<<<<<< HEAD
174176
"health_check": {
175177
Type: schema.TypeSet,
176178
Optional: true,
@@ -205,6 +207,30 @@ func ResourceContainer() *schema.Resource {
205207
DiffSuppressFunc: dsf.Duration,
206208
ValidateDiagFunc: verify.IsDuration(),
207209
Required: true,
210+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
211+
=======
212+
"scaling_option": {
213+
Type: schema.TypeSet,
214+
Optional: true,
215+
Computed: true,
216+
Description: "Configuration used to decide when to scale up or down.",
217+
Elem: &schema.Resource{
218+
Schema: map[string]*schema.Schema{
219+
"concurrent_requests_threshold": {
220+
Type: schema.TypeInt,
221+
Description: "Scale depending on the number of concurrent requests being processed per container instance.",
222+
Optional: true,
223+
},
224+
"cpu_usage_threshold": {
225+
Type: schema.TypeInt,
226+
Description: "Scale depending on the CPU usage of a container instance.",
227+
Optional: true,
228+
},
229+
"memory_usage_threshold": {
230+
Type: schema.TypeInt,
231+
Description: "Scale depending on the memory usage of a container instance.",
232+
Optional: true,
233+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
208234
},
209235
},
210236
},
@@ -322,7 +348,12 @@ func ResourceContainerRead(ctx context.Context, d *schema.ResourceData, m interf
322348
_ = d.Set("deploy", scw.BoolPtr(*types.ExpandBoolPtr(d.Get("deploy"))))
323349
_ = d.Set("http_option", co.HTTPOption)
324350
_ = d.Set("sandbox", co.Sandbox)
351+
<<<<<<< HEAD
325352
_ = d.Set("health_check", flattenHealthCheck(co.HealthCheck))
353+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
354+
=======
355+
_ = d.Set("scaling_option", flattenScalingOption(co.ScalingOption))
356+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
326357
_ = d.Set("region", co.Region.String())
327358

328359
return nil
@@ -418,6 +449,7 @@ func ResourceContainerUpdate(ctx context.Context, d *schema.ResourceData, m inte
418449
req.Sandbox = container.ContainerSandbox(d.Get("sandbox").(string))
419450
}
420451

452+
<<<<<<< HEAD
421453
if d.HasChanges("health_check") {
422454
healthCheck := d.Get("health_check")
423455

@@ -427,6 +459,17 @@ func ResourceContainerUpdate(ctx context.Context, d *schema.ResourceData, m inte
427459
}
428460

429461
req.HealthCheck = healthCheckReq
462+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
463+
=======
464+
if d.HasChanges("scaling_option") {
465+
scalingOption := d.Get("scaling_option")
466+
467+
scalingOptionReq, err := expandScalingOptions(scalingOption)
468+
if err != nil {
469+
return diag.FromErr(err)
470+
}
471+
req.ScalingOption = scalingOptionReq
472+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
430473
}
431474

432475
imageHasChanged := d.HasChanges("registry_sha256")

internal/services/container/container_data_source_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func TestAccDataSourceContainer_Basic(t *testing.T) {
5050
})
5151
}
5252

53+
<<<<<<< HEAD
5354
func TestAccDataSourceContainer_HealthCheck(t *testing.T) {
5455
tt := acctest.NewTestTools(t)
5556
defer tt.Cleanup()
@@ -82,6 +83,38 @@ func TestAccDataSourceContainer_HealthCheck(t *testing.T) {
8283
resource.TestCheckResourceAttr("data.scaleway_container.main", "health_check.#", "1"),
8384
resource.TestCheckResourceAttr("data.scaleway_container.main", "health_check.0.failure_threshold", "30"),
8485
resource.TestCheckResourceAttr("data.scaleway_container.main", "health_check.0.interval", "10s"),
86+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
87+
=======
88+
func TestAccDataSourceContainer_ScalingOption(t *testing.T) {
89+
tt := acctest.NewTestTools(t)
90+
defer tt.Cleanup()
91+
resource.ParallelTest(t, resource.TestCase{
92+
PreCheck: func() { acctest.PreCheck(t) },
93+
ProviderFactories: tt.ProviderFactories,
94+
CheckDestroy: isNamespaceDestroyed(tt),
95+
Steps: []resource.TestStep{
96+
{
97+
Config: `
98+
resource scaleway_container_namespace main {}
99+
100+
resource scaleway_container main {
101+
namespace_id = scaleway_container_namespace.main.id
102+
deploy = false
103+
}
104+
105+
data scaleway_container main {
106+
namespace_id = scaleway_container_namespace.main.id
107+
container_id = scaleway_container.main.id
108+
}
109+
`,
110+
Check: resource.ComposeTestCheckFunc(
111+
isContainerPresent(tt, "scaleway_container.main"),
112+
// Check default option returned by the API when you don't specify the scaling_option block.
113+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.#", "1"),
114+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.0.concurrent_requests_threshold", "50"),
115+
resource.TestCheckResourceAttr("data.scaleway_container.main", "scaling_option.#", "1"),
116+
resource.TestCheckResourceAttr("data.scaleway_container.main", "scaling_option.0.concurrent_requests_threshold", "50"),
117+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
85118
),
86119
},
87120
},

internal/services/container/container_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ func TestAccContainer_Sandbox(t *testing.T) {
400400
})
401401
}
402402

403+
<<<<<<< HEAD
403404
func TestAccContainer_HealthCheck(t *testing.T) {
404405
tt := acctest.NewTestTools(t)
405406
defer tt.Cleanup()
@@ -448,6 +449,92 @@ func TestAccContainer_HealthCheck(t *testing.T) {
448449
resource.TestCheckResourceAttr("scaleway_container.main", "health_check.0.http.0.path", "/test"),
449450
resource.TestCheckResourceAttr("scaleway_container.main", "health_check.0.failure_threshold", "40"),
450451
resource.TestCheckResourceAttr("scaleway_container.main", "health_check.0.interval", "12s"),
452+
||||||| parent of d04ca3f0 (feat(container/serverless): add scaling_option block)
453+
=======
454+
func TestAccContainer_ScalingOption(t *testing.T) {
455+
tt := acctest.NewTestTools(t)
456+
defer tt.Cleanup()
457+
resource.ParallelTest(t, resource.TestCase{
458+
PreCheck: func() { acctest.PreCheck(t) },
459+
ProviderFactories: tt.ProviderFactories,
460+
CheckDestroy: isContainerDestroyed(tt),
461+
Steps: []resource.TestStep{
462+
{
463+
Config: `
464+
resource scaleway_container_namespace main {}
465+
466+
resource scaleway_container main {
467+
namespace_id = scaleway_container_namespace.main.id
468+
deploy = false
469+
}
470+
`,
471+
Check: resource.ComposeTestCheckFunc(
472+
isContainerPresent(tt, "scaleway_container.main"),
473+
// Check default option returned by the API when you don't specify the scaling_option block.
474+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.#", "1"),
475+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.0.concurrent_requests_threshold", "50"),
476+
),
477+
},
478+
{
479+
Config: `
480+
resource scaleway_container_namespace main {}
481+
482+
resource scaleway_container main {
483+
namespace_id = scaleway_container_namespace.main.id
484+
deploy = false
485+
486+
scaling_option {
487+
concurrent_requests_threshold = 15
488+
}
489+
}
490+
`,
491+
Check: resource.ComposeTestCheckFunc(
492+
isContainerPresent(tt, "scaleway_container.main"),
493+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.#", "1"),
494+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.0.concurrent_requests_threshold", "15"),
495+
),
496+
},
497+
{
498+
Config: `
499+
resource scaleway_container_namespace main {}
500+
501+
resource scaleway_container main {
502+
namespace_id = scaleway_container_namespace.main.id
503+
deploy = false
504+
505+
min_scale = 1
506+
507+
scaling_option {
508+
cpu_usage_threshold = 72
509+
}
510+
}
511+
`,
512+
Check: resource.ComposeTestCheckFunc(
513+
isContainerPresent(tt, "scaleway_container.main"),
514+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.#", "1"),
515+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.0.cpu_usage_threshold", "72"),
516+
),
517+
},
518+
519+
{
520+
Config: `
521+
resource scaleway_container_namespace main {}
522+
523+
resource scaleway_container main {
524+
namespace_id = scaleway_container_namespace.main.id
525+
deploy = false
526+
527+
min_scale = 1
528+
529+
scaling_option {
530+
memory_usage_threshold = 66
531+
}
532+
}
533+
`,
534+
Check: resource.ComposeTestCheckFunc(
535+
isContainerPresent(tt, "scaleway_container.main"),
536+
resource.TestCheckResourceAttr("scaleway_container.main", "scaling_option.0.memory_usage_threshold", "66"),
537+
>>>>>>> d04ca3f0 (feat(container/serverless): add scaling_option block)
451538
),
452539
},
453540
},

internal/services/container/helpers_container.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ func setCreateContainerRequest(d *schema.ResourceData, region scw.Region) (*cont
126126
req.HealthCheck = healthCheckReq
127127
}
128128

129+
if scalingOption, ok := d.GetOk("scaling_option"); ok {
130+
scalingOptionReq, err := expandScalingOptions(scalingOption)
131+
if err != nil {
132+
return nil, err
133+
}
134+
req.ScalingOption = scalingOptionReq
135+
}
136+
129137
return req, nil
130138
}
131139

@@ -220,6 +228,57 @@ func flattenHealthCheckHTTP(healthCheckHTTP *container.ContainerHealthCheckSpecH
220228
return flattenedHealthCheckHTTP
221229
}
222230

231+
func expandScalingOptions(scalingOptionSchema interface{}) (*container.ContainerScalingOption, error) {
232+
scalingOption, ok := scalingOptionSchema.(*schema.Set)
233+
if !ok {
234+
return &container.ContainerScalingOption{}, nil
235+
}
236+
237+
for _, option := range scalingOption.List() {
238+
rawOption, isRawOption := option.(map[string]interface{})
239+
if !isRawOption {
240+
continue
241+
}
242+
243+
setFields := 0
244+
cso := &container.ContainerScalingOption{}
245+
if concurrentRequestThresold, ok := rawOption["concurrent_requests_threshold"].(int); ok && concurrentRequestThresold != 0 {
246+
cso.ConcurrentRequestsThreshold = scw.Uint32Ptr(uint32(concurrentRequestThresold))
247+
setFields++
248+
}
249+
if cpuUsageThreshold, ok := rawOption["cpu_usage_threshold"].(int); ok && cpuUsageThreshold != 0 {
250+
cso.CPUUsageThreshold = scw.Uint32Ptr(uint32(cpuUsageThreshold))
251+
setFields++
252+
}
253+
if memoryUsageThreshold, ok := rawOption["memory_usage_threshold"].(int); ok && memoryUsageThreshold != 0 {
254+
cso.MemoryUsageThreshold = scw.Uint32Ptr(uint32(memoryUsageThreshold))
255+
setFields++
256+
}
257+
258+
if setFields > 1 {
259+
return &container.ContainerScalingOption{}, errors.New("a maximum of one scaling option can be set")
260+
}
261+
return cso, nil
262+
}
263+
264+
return &container.ContainerScalingOption{}, nil
265+
}
266+
267+
func flattenScalingOption(scalingOption *container.ContainerScalingOption) interface{} {
268+
if scalingOption == nil {
269+
return nil
270+
}
271+
272+
flattenedScalingOption := []map[string]interface{}(nil)
273+
flattenedScalingOption = append(flattenedScalingOption, map[string]interface{}{
274+
"concurrent_requests_threshold": types.FlattenUint32Ptr(scalingOption.ConcurrentRequestsThreshold),
275+
"cpu_usage_threshold": types.FlattenUint32Ptr(scalingOption.CPUUsageThreshold),
276+
"memory_usage_threshold": types.FlattenUint32Ptr(scalingOption.MemoryUsageThreshold),
277+
})
278+
279+
return flattenedScalingOption
280+
}
281+
223282
func expandContainerSecrets(secretsRawMap interface{}) []*container.Secret {
224283
secretsMap := secretsRawMap.(map[string]interface{})
225284
secrets := make([]*container.Secret, 0, len(secretsMap))

0 commit comments

Comments
 (0)