Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions docs/resources/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ resource "scaleway_container" "main" {
protocol = "http1"
deploy = true

command = [ "bash", "-c", "script.sh" ]
args = [ "some", "args" ]

environment_variables = {
"foo" = "var"
}
Expand Down Expand Up @@ -104,6 +107,10 @@ The following arguments are supported:

- `local_storage_limit` - (Optional) Local storage limit of the container (in MB)

- `command` - (Optional) Command executed when the container starts. This overrides the default command defined in the container image. This is usually the main executable, or entry point script to run.

- `args` - (Optional) Arguments passed to the command specified in the "command" field. These override the default arguments from the container image, and behave like command-line parameters.

Note that if you want to use your own configuration, you must consult our configuration [restrictions](https://www.scaleway.com/en/docs/serverless-containers/reference-content/containers-limitations/#configuration-restrictions) section.

## Attributes Reference
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/nats-io/jwt/v2 v2.7.4
github.com/nats-io/nats.go v1.38.0
github.com/robfig/cron/v3 v3.0.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250610081511-58ce335a6dea
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.38.0
gopkg.in/dnaeon/go-vcr.v3 v3.2.0
Expand Down Expand Up @@ -154,13 +154,13 @@ require (
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.30.0 // indirect
golang.org/x/tools v0.33.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b h1:wzu3hPSNK2PPo7OXBzofeS5hOWqnVRP8xqIXom9ufoc=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b/go.mod h1:qiGzapFyNPFwBBLJ+hTFykKSnU95n1zL64+o1ubmwf0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250610081511-58ce335a6dea h1:xP1NE2ZcMvPLRsGOPJnrdSkRqlNpCLFs1p3+WzerS9w=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250610081511-58ce335a6dea/go.mod h1:zFWiHphneiey3s8HOtAEnGrRlWivNaxW5T6d5Xfco7g=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
Expand Down Expand Up @@ -587,8 +587,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -624,8 +624,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -647,8 +647,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -720,8 +720,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down Expand Up @@ -780,8 +780,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
121 changes: 17 additions & 104 deletions internal/services/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,18 @@ func ResourceContainer() *schema.Resource {
Optional: true,
Computed: true,
},
"command": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Description: "Command executed when the container starts. Overrides the command from the container image.",
},
"args": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Description: "Arguments passed to the command from the command \"field\". Overrides the arguments from the container image.",
},
// computed
"status": {
Type: schema.TypeString,
Expand Down Expand Up @@ -370,6 +382,8 @@ func ResourceContainerRead(ctx context.Context, d *schema.ResourceData, m interf
_ = d.Set("local_storage_limit", int(co.LocalStorageLimit))
_ = d.Set("secret_environment_variables", flattenContainerSecrets(co.SecretEnvironmentVariables))
_ = d.Set("tags", types.FlattenSliceString(co.Tags))
_ = d.Set("command", types.FlattenSliceString(co.Command))
_ = d.Set("args", types.FlattenSliceString(co.Args))

return nil
}
Expand All @@ -394,110 +408,9 @@ func ResourceContainerUpdate(ctx context.Context, d *schema.ResourceData, m inte
}

// update container
req := &container.UpdateContainerRequest{
Region: region,
ContainerID: containerID,
}

if d.HasChanges("environment_variables") {
envVariablesRaw := d.Get("environment_variables")
req.EnvironmentVariables = types.ExpandMapPtrStringString(envVariablesRaw)
}

if d.HasChanges("secret_environment_variables") {
oldEnv, newEnv := d.GetChange("secret_environment_variables")
req.SecretEnvironmentVariables = filterSecretEnvsToPatch(expandContainerSecrets(oldEnv), expandContainerSecrets(newEnv))
}

if d.HasChange("tags") {
req.Tags = types.ExpandUpdatedStringsPtr(d.Get("tags"))
}

if d.HasChanges("min_scale") {
req.MinScale = scw.Uint32Ptr(uint32(d.Get("min_scale").(int)))
}

if d.HasChanges("max_scale") {
req.MaxScale = scw.Uint32Ptr(uint32(d.Get("max_scale").(int)))
}

if d.HasChanges("memory_limit") {
req.MemoryLimit = scw.Uint32Ptr(uint32(d.Get("memory_limit").(int)))
}

if d.HasChanges("cpu_limit") {
req.CPULimit = scw.Uint32Ptr(uint32(d.Get("cpu_limit").(int)))
}

if d.HasChanges("timeout") {
req.Timeout = &scw.Duration{Seconds: int64(d.Get("timeout").(int))}
}

if d.HasChanges("privacy") {
req.Privacy = container.ContainerPrivacy(*types.ExpandStringPtr(d.Get("privacy")))
}

if d.HasChanges("description") {
req.Description = types.ExpandUpdatedStringPtr(d.Get("description"))
}

if d.HasChanges("registry_image") {
req.RegistryImage = types.ExpandStringPtr(d.Get("registry_image"))
}

if d.HasChanges("max_concurrency") {
req.MaxConcurrency = scw.Uint32Ptr(uint32(d.Get("max_concurrency").(int))) //nolint:staticcheck
}

if d.HasChanges("protocol") {
req.Protocol = container.ContainerProtocol(*types.ExpandStringPtr(d.Get("protocol")))
}

if d.HasChanges("port") {
req.Port = scw.Uint32Ptr(uint32(d.Get("port").(int)))
}

if d.HasChanges("http_option") {
req.HTTPOption = container.ContainerHTTPOption(d.Get("http_option").(string))
}

if d.HasChanges("deploy") {
req.Redeploy = types.ExpandBoolPtr(d.Get("deploy"))
}

if d.HasChanges("sandbox") {
req.Sandbox = container.ContainerSandbox(d.Get("sandbox").(string))
}

if d.HasChanges("health_check") {
healthCheck := d.Get("health_check")

healthCheckReq, errExpandHealthCheck := expandHealthCheck(healthCheck)
if errExpandHealthCheck != nil {
return diag.FromErr(errExpandHealthCheck)
}

req.HealthCheck = healthCheckReq
}

if d.HasChanges("scaling_option") {
scalingOption := d.Get("scaling_option")

scalingOptionReq, err := expandScalingOptions(scalingOption)
if err != nil {
return diag.FromErr(err)
}

req.ScalingOption = scalingOptionReq
}

imageHasChanged := d.HasChanges("registry_sha256")
if imageHasChanged {
req.Redeploy = &imageHasChanged
}

if d.HasChanges("local_storage_limit") {
req.LocalStorageLimit = scw.Uint32Ptr(uint32(d.Get("local_storage_limit").(int)))
req, err := setUpdateContainerRequest(d, region, containerID)
if err != nil {
return diag.FromErr(err)
}

con, err := api.UpdateContainer(req, scw.WithContext(ctx))
Expand Down
82 changes: 82 additions & 0 deletions internal/services/container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,88 @@ func TestAccContainer_ScalingOption(t *testing.T) {
})
}

func TestAccContainer_CommandAndArgs(t *testing.T) {
tt := acctest.NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: isContainerDestroyed(tt),
Steps: []resource.TestStep{
{
Config: `
resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
command = [ "bash", "-c", "my-script.sh" ]
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.main"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.#", "3"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.0", "bash"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.1", "-c"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.2", "my-script.sh"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.#", "0"),
),
},
{
Config: `
resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
command = [ "bash", "-c", "my-script.sh" ]
args = [ "some", "args" ]
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.main"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.#", "3"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.0", "bash"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.1", "-c"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.2", "my-script.sh"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.#", "2"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.0", "some"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.1", "args"),
),
},
{
Config: `
resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
args = [ "some", "args" ]
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.main"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.#", "0"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.#", "2"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.0", "some"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.1", "args"),
),
},
{
Config: `
resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.main"),
resource.TestCheckResourceAttr("scaleway_container.main", "command.#", "0"),
resource.TestCheckResourceAttr("scaleway_container.main", "args.#", "0"),
),
},
},
})
}

func isContainerPresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
return func(state *terraform.State) error {
rs, ok := state.RootModule().Resources[n]
Expand Down
Loading
Loading