Skip to content

Commit

Permalink
feat(container-cron): add new resource container cron (#1329)
Browse files Browse the repository at this point in the history
  • Loading branch information
Monitob committed Jun 28, 2022
1 parent 3c553ab commit 21dc4f5
Show file tree
Hide file tree
Showing 14 changed files with 2,587 additions and 267 deletions.
2 changes: 1 addition & 1 deletion docs/resources/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ In addition to all above arguments, the following attributes are exported:

## Import

Container can be imported using the container_name, e.g.,
Container can be imported using the `{region}/{id}`, e.g.

```bash
$ terraform import scaleway_container.main fr-par/11111111-1111-1111-1111-111111111111
Expand Down
80 changes: 80 additions & 0 deletions docs/resources/container_cron.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
page_title: "Scaleway: scaleway_container_cron"
description: |-
Manages Scaleway Containers Triggers.
---

# scaleway_container_cron

Creates and manages Scaleway Container Triggers. For the moment, the feature is limited to CRON Schedule (time-based).

For more information consult
the [documentation](https://www.scaleway.com/en/docs/compute/containers/api-cli/cont-uploading-with-serverless-framework/#configuring-events)
.

For more details about the limitation
check [containers-limitations](https://www.scaleway.com/en/docs/compute/containers/reference-content/containers-limitations/)
.

You can check also
our [containers cron api documentation](https://developers.scaleway.com/en/products/containers/api/#crons-942bf4).

## Example Usage

```hcl
resource scaleway_container_namespace main {
}
resource scaleway_container main {
name = "my-container-with-cron-tf"
namespace_id = scaleway_container_namespace.main.id
}
resource scaleway_container_cron main {
container_id = scaleway_container.main.id
schedule = "5 4 1 * *" #cron at 04:05 on day-of-month 1
args = jsonencode(
{
address = {
city = "Paris"
country = "FR"
}
age = 23
firstName = "John"
isAlive = true
lastName = "Smith"
# minScale: 1
# memoryLimit: 256
# maxScale: 2
# timeout: 20000
# Local environment variables - used only in given function
}
)
}
```

## Arguments Reference

The following arguments are required:

- `schedule` - (Required) Cron format string, e.g. @hourly, as schedule time of its jobs to be created and
executed.
- `container_id` - (Required) The container ID to link with your cron.
- `args` - (Required) The key-value mapping to define arguments that will be passed to your container’s event object
during

## Attributes Reference

In addition to all above arguments, the following attributes are exported:

- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions)
in where the job was created.
- `status` - The cron status.

## Import

Container Cron can be imported using the `{region}/{id}`, e.g.

```bash
$ terraform import scaleway_container_cron.main fr-par/11111111-1111-1111-1111-111111111111
```
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hashicorp/terraform-plugin-log v0.4.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.17.0
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f
github.com/robfig/cron/v3 v3.0.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624140600-38685b7aadbb
github.com/stretchr/testify v1.7.1
)

Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,11 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220616135310-b11a2a9a6c76 h1:FjeyXcr7eAD4GkstU4ZrpM+GJq8t0zo5h1BwknvJKB8=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220616135310-b11a2a9a6c76/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f h1:wLBnkc5V6oq/u9ep7FIpUHzl2vgaURY+Dr2Mp/7Rv/c=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624101230-756b7ec05a7f/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624140600-38685b7aadbb h1:47x0la4woy6fwiU5xcahypU6NCcfnprcrW39rWJCuDI=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9.0.20220624140600-38685b7aadbb/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
Expand Down
38 changes: 36 additions & 2 deletions scaleway/helpers_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (

const (
defaultContainerNamespaceTimeout = 5 * time.Minute
defaultContainerCronTimeout = 5 * time.Minute
defaultContainerTimeout = 5 * time.Minute
defaultContainerRetryInterval = 5 * time.Second
)

Expand Down Expand Up @@ -100,18 +102,50 @@ func setCreateContainerRequest(d *schema.ResourceData, region scw.Region) (*cont
return req, nil
}

func waitForContainerNamespace(ctx context.Context, containerAPI *container.API, region scw.Region, id string, timeout time.Duration) (*container.Namespace, error) {
func waitForContainerNamespace(ctx context.Context, containerAPI *container.API, region scw.Region, namespaceID string, timeout time.Duration) (*container.Namespace, error) {
retryInterval := defaultContainerRetryInterval
if DefaultWaitRetryInterval != nil {
retryInterval = *DefaultWaitRetryInterval
}

ns, err := containerAPI.WaitForNamespace(&container.WaitForNamespaceRequest{
Region: region,
NamespaceID: id,
NamespaceID: namespaceID,
RetryInterval: &retryInterval,
Timeout: scw.TimeDurationPtr(timeout),
}, scw.WithContext(ctx))

return ns, err
}

func waitForContainerCron(ctx context.Context, api *container.API, cronID string, region scw.Region, timeout time.Duration) (*container.Cron, error) {
retryInterval := defaultContainerRetryInterval
if DefaultWaitRetryInterval != nil {
retryInterval = *DefaultWaitRetryInterval
}

request := container.WaitForCronRequest{
CronID: cronID,
Region: region,
Timeout: scw.TimeDurationPtr(timeout),
RetryInterval: &retryInterval,
}

return api.WaitForCron(&request, scw.WithContext(ctx))
}

func waitForContainer(ctx context.Context, api *container.API, containerID string, region scw.Region, timeout time.Duration) (*container.Container, error) {
retryInterval := defaultContainerRetryInterval
if DefaultWaitRetryInterval != nil {
retryInterval = *DefaultWaitRetryInterval
}

request := container.WaitForContainerRequest{
ContainerID: containerID,
Region: region,
Timeout: scw.TimeDurationPtr(timeout),
RetryInterval: &retryInterval,
}

return api.WaitForContainer(&request, scw.WithContext(ctx))
}
1 change: 1 addition & 0 deletions scaleway/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
"scaleway_apple_silicon_server": resourceScalewayAppleSiliconServer(),
"scaleway_baremetal_server": resourceScalewayBaremetalServer(),
"scaleway_container_namespace": resourceScalewayContainerNamespace(),
"scaleway_container_cron": resourceScalewayContainerCron(),
"scaleway_domain_record": resourceScalewayDomainRecord(),
"scaleway_domain_zone": resourceScalewayDomainZone(),
"scaleway_function": resourceScalewayFunction(),
Expand Down
89 changes: 29 additions & 60 deletions scaleway/resource_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ func resourceScalewayContainer() *schema.Resource {
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Default: schema.DefaultTimeout(defaultContainerNamespaceTimeout),
Create: schema.DefaultTimeout(defaultContainerTimeout),
Read: schema.DefaultTimeout(defaultContainerTimeout),
Update: schema.DefaultTimeout(defaultContainerTimeout),
Delete: schema.DefaultTimeout(defaultContainerTimeout),
Default: schema.DefaultTimeout(defaultContainerTimeout),
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -167,14 +171,9 @@ func resourceScalewayContainerCreate(ctx context.Context, d *schema.ResourceData
if region.String() == "" {
region = scw.RegionFrPar
}
namespaceID := d.Get("namespace_id")
namespaceID := expandID(d.Get("namespace_id").(string))
// verify name space state
_, err = api.WaitForNamespace(&container.WaitForNamespaceRequest{
NamespaceID: expandID(namespaceID),
Region: region,
Timeout: scw.TimeDurationPtr(defaultRegistryNamespaceTimeout),
RetryInterval: DefaultWaitRetryInterval,
}, scw.WithContext(ctx))
_, err = waitForContainerNamespace(ctx, api, region, namespaceID, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.Errorf("unexpected namespace error: %s", err)
}
Expand All @@ -192,10 +191,7 @@ func resourceScalewayContainerCreate(ctx context.Context, d *schema.ResourceData
// check if container should be deployed
shouldDeploy := d.Get("deploy")
if *expandBoolPtr(shouldDeploy) {
_, err := api.WaitForContainer(&container.WaitForContainerRequest{
ContainerID: res.ID,
Region: region,
}, scw.WithContext(ctx))
_, err = waitForContainer(ctx, api, res.ID, region, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.Errorf("unexpected waiting container error: %s", err)
}
Expand All @@ -209,6 +205,11 @@ func resourceScalewayContainerCreate(ctx context.Context, d *schema.ResourceData
if err != nil {
return diag.FromErr(err)
}

_, err = waitForContainer(ctx, api, res.ID, region, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.Errorf("unexpected waiting container error: %s", err)
}
}

d.SetId(newRegionalIDString(region, res.ID))
Expand All @@ -222,11 +223,12 @@ func resourceScalewayContainerRead(ctx context.Context, d *schema.ResourceData,
return diag.FromErr(err)
}

co, err := api.WaitForContainer(&container.WaitForContainerRequest{
ContainerID: containerID,
Region: region,
}, scw.WithContext(ctx))
co, err := waitForContainer(ctx, api, containerID, region, d.Timeout(schema.TimeoutCreate))
if err != nil {
if is404Error(err) {
d.SetId("")
return nil
}
return diag.Errorf("unexpected waiting container error: %s", err)
}

Expand Down Expand Up @@ -262,52 +264,17 @@ func resourceScalewayContainerUpdate(ctx context.Context, d *schema.ResourceData

namespaceID := d.Get("namespace_id")
// verify name space state
_, err = api.WaitForNamespace(&container.WaitForNamespaceRequest{
NamespaceID: expandID(namespaceID),
Region: region,
}, scw.WithContext(ctx))
_, err = waitForContainerNamespace(ctx, api, region, expandID(namespaceID), d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.Errorf("unexpected namespace error: %s", err)
}

// check for container state
_, err = api.WaitForContainer(&container.WaitForContainerRequest{
ContainerID: containerID,
Region: region,
}, scw.WithContext(ctx))
_, err = waitForContainer(ctx, api, containerID, region, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.Errorf("unexpected waiting container error: %s", err)
}

// Warning or Errors can be collected as warnings
var diags diag.Diagnostics

// check triggers associated
triggers, err := api.ListCrons(&container.ListCronsRequest{
Region: region,
ContainerID: containerID,
}, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

// wait for triggers state
for _, c := range triggers.Crons {
_, err := api.WaitForCron(&container.WaitForCronRequest{
CronID: c.ID,
Region: region,
Timeout: scw.TimeDurationPtr(defaultContainerNamespaceTimeout),
RetryInterval: DefaultWaitRetryInterval,
}, scw.WithContext(ctx))
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Warning waiting cron job",
Detail: err.Error(),
})
}
}

// update container
req := &container.UpdateContainerRequest{
Region: region,
Expand Down Expand Up @@ -368,12 +335,17 @@ func resourceScalewayContainerUpdate(ctx context.Context, d *schema.ResourceData
req.Redeploy = expandBoolPtr(d.Get("deploy"))
}

_, err = api.UpdateContainer(req, scw.WithContext(ctx))
con, err := api.UpdateContainer(req, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

return append(diags, resourceScalewayContainerRead(ctx, d, meta)...)
_, err = waitForContainer(ctx, api, con.ID, region, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(err)
}

return resourceScalewayContainerRead(ctx, d, meta)
}

func resourceScalewayContainerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand All @@ -383,12 +355,9 @@ func resourceScalewayContainerDelete(ctx context.Context, d *schema.ResourceData
}

// check for container state
_, err = api.WaitForContainer(&container.WaitForContainerRequest{
ContainerID: containerID,
Region: region,
}, scw.WithContext(ctx))
_, err = waitForContainer(ctx, api, containerID, region, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.Errorf("unexpected waiting container error: %s", err)
return diag.FromErr(err)
}

// delete container
Expand Down

0 comments on commit 21dc4f5

Please sign in to comment.