Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions docs/resources/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ The following arguments are supported:

- `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.

- `private_network_id` (Optional) The ID of the Private Network the container is connected to.

~> **Important** This feature is currently in beta and requires a namespace with VPC integration activated by setting the `activate_vpc_integration` attribute to `true`.

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
4 changes: 4 additions & 0 deletions docs/resources/container_namespace.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ The following arguments are supported:

- `secret_environment_variables` - (Optional) The secret environment variables of the namespace.

- `activate_vpc_integration` - (Optional) Activates VPC integration for the namespace. Containers of a namespace with VPC integration activated will be able to connect to a Private Network.

~> **Important** Updates to `activate_vpc_integration` will recreate the namespace.

## Attributes Reference

The `scaleway_container_namespace` resource exports certain attributes once the Containers namespace has been created. These attributes can be referenced in other parts of your Terraform configuration.
Expand Down
1 change: 1 addition & 0 deletions internal/acctest/validate_cassettes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func exceptionsCassettesCases() map[string]struct{} {
"../services/secret/testdata/secret-version-type.cassette.yaml": {},
"../services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml": {},
"../services/file/testdata/file-system-size-too-small-fails.cassette.yaml": {},
"../services/container/testdata/namespace-vpc-integration.cassette.yaml": {},
"../services/function/testdata/function-namespace-vpc-integration.cassette.yaml": {},
}
}
Expand Down
12 changes: 12 additions & 0 deletions internal/services/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func ResourceContainer() *schema.Resource {
"namespace_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The container namespace associated",
},
"tags": {
Expand Down Expand Up @@ -263,6 +264,11 @@ func ResourceContainer() *schema.Resource {
Optional: true,
Description: "Arguments passed to the command from the command \"field\". Overrides the arguments from the container image.",
},
"private_network_id": {
Type: schema.TypeString,
Optional: true,
Description: "ID of the Private Network the container is connected to",
},
// computed
"status": {
Type: schema.TypeString,
Expand Down Expand Up @@ -385,6 +391,12 @@ func ResourceContainerRead(ctx context.Context, d *schema.ResourceData, m any) d
_ = d.Set("command", types.FlattenSliceString(co.Command))
_ = d.Set("args", types.FlattenSliceString(co.Args))

if co.PrivateNetworkID != nil {
_ = d.Set("private_network_id", regional.NewID(region, types.FlattenStringPtr(co.PrivateNetworkID).(string)).String())
} else {
_ = d.Set("private_network_id", nil)
}

return nil
}

Expand Down
132 changes: 132 additions & 0 deletions internal/services/container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/container"
vpcchecks "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/vpc/testfuncs"
)

func TestAccContainer_Basic(t *testing.T) {
Expand Down Expand Up @@ -625,6 +626,137 @@ func TestAccContainer_CommandAndArgs(t *testing.T) {
})
}

func TestAccContainer_PrivateNetwork(t *testing.T) {
tt := acctest.NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: resource.ComposeTestCheckFunc(
isNamespaceDestroyed(tt),
isContainerDestroyed(tt),
vpcchecks.CheckPrivateNetworkDestroy(tt),
),
Steps: []resource.TestStep{
{
Config: `
resource scaleway_vpc_private_network pn00 {
name = "test-acc-container-pn-pn00"
}
resource scaleway_vpc_private_network pn01 {
name = "test-acc-container-pn-pn01"
}

resource scaleway_container_namespace main {
activate_vpc_integration = true
}

resource scaleway_container c00 {
name = "test-acc-container-pn-c00"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn00.id
sandbox = "v1"
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.c00"),
resource.TestCheckResourceAttr("scaleway_container_namespace.main", "activate_vpc_integration", "true"),
resource.TestCheckResourceAttr("scaleway_container.c00", "sandbox", "v1"),
resource.TestCheckResourceAttrPair("scaleway_container.c00", "private_network_id", "scaleway_vpc_private_network.pn00", "id"),
),
},
{
Config: `
resource scaleway_vpc_private_network pn00 {
name = "test-acc-container-pn-pn00"
}
resource scaleway_vpc_private_network pn01 {
name = "test-acc-container-pn-pn01"
}

resource scaleway_container_namespace main {
activate_vpc_integration = true
}

resource scaleway_container c00 {
name = "test-acc-container-pn-c00"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn00.id
sandbox = "v1"
}

resource scaleway_container c01 {
name = "test-acc-container-pn-c01"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn00.id
sandbox = "v1"
}

resource scaleway_container c02 {
name = "test-acc-container-pn-c02"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn00.id
sandbox = "v1"
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.c00"),
isContainerPresent(tt, "scaleway_container.c01"),
isContainerPresent(tt, "scaleway_container.c02"),
resource.TestCheckResourceAttr("scaleway_container.c00", "sandbox", "v1"),
resource.TestCheckResourceAttr("scaleway_container.c01", "sandbox", "v1"),
resource.TestCheckResourceAttr("scaleway_container.c02", "sandbox", "v1"),
resource.TestCheckResourceAttrPair("scaleway_container.c00", "private_network_id", "scaleway_vpc_private_network.pn00", "id"),
resource.TestCheckResourceAttrPair("scaleway_container.c01", "private_network_id", "scaleway_vpc_private_network.pn00", "id"),
resource.TestCheckResourceAttrPair("scaleway_container.c02", "private_network_id", "scaleway_vpc_private_network.pn00", "id"),
),
},
{
Config: `
resource scaleway_vpc_private_network pn00 {
name = "test-acc-container-pn-pn00"
}
resource scaleway_vpc_private_network pn01 {
name = "test-acc-container-pn-pn01"
}

resource scaleway_container_namespace main {
activate_vpc_integration = true
}

resource scaleway_container c00 {
name = "test-acc-container-pn-c00"
namespace_id = scaleway_container_namespace.main.id
sandbox = "v1"
}

resource scaleway_container c01 {
name = "test-acc-container-pn-c01"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn01.id
sandbox = "v1"
}

resource scaleway_container c02 {
name = "test-acc-container-pn-c02"
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.pn00.id
sandbox = "v1"
}
`,
Check: resource.ComposeTestCheckFunc(
isContainerPresent(tt, "scaleway_container.c00"),
isContainerPresent(tt, "scaleway_container.c01"),
isContainerPresent(tt, "scaleway_container.c02"),
resource.TestCheckResourceAttr("scaleway_container.c00", "private_network_id", ""),
resource.TestCheckResourceAttrPair("scaleway_container.c01", "private_network_id", "scaleway_vpc_private_network.pn01", "id"),
resource.TestCheckResourceAttrPair("scaleway_container.c02", "private_network_id", "scaleway_vpc_private_network.pn00", "id"),
),
},
},
})
}

func isContainerPresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
return func(state *terraform.State) error {
rs, ok := state.RootModule().Resources[n]
Expand Down
8 changes: 8 additions & 0 deletions internal/services/container/helpers_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ func setCreateContainerRequest(d *schema.ResourceData, region scw.Region) (*cont
req.Args = types.ExpandStrings(args)
}

if pnID, ok := d.GetOk("private_network_id"); ok {
req.PrivateNetworkID = types.ExpandStringPtr(locality.ExpandID(pnID.(string)))
}

return req, nil
}

Expand Down Expand Up @@ -270,6 +274,10 @@ func setUpdateContainerRequest(d *schema.ResourceData, region scw.Region, contai
req.Args = types.ExpandUpdatedStringsPtr(d.Get("args"))
}

if d.HasChanges("private_network_id") {
req.PrivateNetworkID = types.ExpandUpdatedStringPtr(locality.ExpandID(d.Get("private_network_id")))
}

return req, nil
}

Expand Down
12 changes: 12 additions & 0 deletions internal/services/container/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ func ResourceNamespace() *schema.Resource {
Description: "Destroy registry on deletion",
Deprecated: "Registry namespace is automatically destroyed with namespace",
},
"activate_vpc_integration": {
Type: schema.TypeBool,
ForceNew: true,
Optional: true,
Default: false,
Description: "Activate VPC integration for the namespace",
},
"region": regional.Schema(),
"organization_id": account.OrganizationIDSchema(),
"project_id": account.ProjectIDSchema(),
Expand Down Expand Up @@ -122,6 +129,10 @@ func ResourceContainerNamespaceCreate(ctx context.Context, d *schema.ResourceDat
createReq.Tags = types.ExpandStrings(rawTag)
}

if activateVPC, ok := d.GetOk("activate_vpc_integration"); ok {
createReq.ActivateVpcIntegration = activateVPC.(bool)
}

ns, err := api.CreateNamespace(createReq, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
Expand Down Expand Up @@ -164,6 +175,7 @@ func ResourceContainerNamespaceRead(ctx context.Context, d *schema.ResourceData,
_ = d.Set("registry_endpoint", ns.RegistryEndpoint)
_ = d.Set("registry_namespace_id", ns.RegistryNamespaceID)
_ = d.Set("secret_environment_variables", flattenContainerSecrets(ns.SecretEnvironmentVariables))
_ = d.Set("activate_vpc_integration", types.FlattenBoolPtr(ns.VpcIntegrationActivated)) //nolint:staticcheck

return nil
}
Expand Down
74 changes: 74 additions & 0 deletions internal/services/container/namespace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package container_test

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/container"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/registry"
vpcchecks "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/vpc/testfuncs"
)

const containerNamespaceResource = "scaleway_container_namespace"
Expand Down Expand Up @@ -265,6 +267,78 @@ func TestAccNamespace_DestroyRegistry(t *testing.T) {
})
}

func TestAccNamespace_VPCIntegration(t *testing.T) {
tt := acctest.NewTestTools(t)
defer tt.Cleanup()

namespaceID := ""

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: resource.ComposeTestCheckFunc(
isNamespaceDestroyed(tt),
isContainerDestroyed(tt),
vpcchecks.CheckPrivateNetworkDestroy(tt),
),
Steps: []resource.TestStep{
{
Config: `
resource scaleway_vpc_private_network main {}

resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
sandbox = "v1"
}
`,
Check: resource.ComposeTestCheckFunc(
isNamespacePresent(tt, "scaleway_container_namespace.main"),
resource.TestCheckResourceAttr("scaleway_container_namespace.main", "activate_vpc_integration", "false"),
acctest.CheckResourceIDPersisted("scaleway_container_namespace.main", &namespaceID),
),
},
{
Config: `
resource scaleway_vpc_private_network main {}

resource scaleway_container_namespace main {}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.main.id
sandbox = "v1"
}
`,
ExpectError: regexp.MustCompile("Application can't be attached to private network, vpc integration must be activated on its parent namespace"),
},
{
Config: `
resource scaleway_vpc_private_network main {}

resource scaleway_container_namespace main {
activate_vpc_integration = true
}

resource scaleway_container main {
namespace_id = scaleway_container_namespace.main.id
private_network_id = scaleway_vpc_private_network.main.id
sandbox = "v1"
}
`,
Check: resource.ComposeTestCheckFunc(
isNamespacePresent(tt, "scaleway_container_namespace.main"),
isContainerPresent(tt, "scaleway_container.main"),
resource.TestCheckResourceAttr("scaleway_container_namespace.main", "activate_vpc_integration", "true"),
resource.TestCheckResourceAttrPair("scaleway_container.main", "private_network_id", "scaleway_vpc_private_network.main", "id"),
acctest.CheckResourceIDChanged("scaleway_container_namespace.main", &namespaceID),
),
},
},
})
}

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