Skip to content

Commit

Permalink
feat(function): add support for cron (#1114)
Browse files Browse the repository at this point in the history
Co-authored-by: jaime Bernabe <6184069+Monitob@users.noreply.github.com>
  • Loading branch information
remyleone and Monitob committed Aug 4, 2022
1 parent aa01160 commit 1cdf057
Show file tree
Hide file tree
Showing 7 changed files with 2,079 additions and 0 deletions.
75 changes: 75 additions & 0 deletions docs/resources/function_cron.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
page_title: "Scaleway: scaleway_function_cron"
description: |-
Manages Scaleway Functions Triggers.
---

# scaleway_function_cron

Creates and manages Scaleway Function 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/functions/api-cli/fun-uploading-with-serverless-framework/#configuring-events)
.

If you want to restrict the access to your function please check [this](https://www.scaleway.com/en/docs/compute/functions/api-cli/restricting-access-to-a-function/).

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

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

## Example Usage

```hcl
resource scaleway_function_namespace main {
name = "test-cron"
}
resource scaleway_function main {
name = "test-cron"
namespace_id = scaleway_function_namespace.main.id
runtime = "node14"
privacy = "private"
handler = "handler.handle"
}
resource scaleway_function_cron main {
function_id = scaleway_function.main.id
schedule = "0 0 * * *"
args = jsonencode({test = "scw"})
}
resource scaleway_function_cron func {
function_id = scaleway_function.main.id
schedule = "0 1 * * *"
args = jsonencode({my_var = "terraform"})
}
```

## 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.
- `function_id` - (Required) The function ID to link with your cron.
- `args` - (Required) The key-value mapping to define arguments that will be passed to your function’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_function_cron.main fr-par/11111111-1111-1111-1111-111111111111
```
15 changes: 15 additions & 0 deletions scaleway/helpers_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
defaultFunctionTimeout = 15 * time.Minute
defaultFunctionRetryInterval = 5 * time.Second
defaultFunctionAfterUpdateWait = 1 * time.Second
defaultFunctionCronTimeout = 5 * time.Minute
)

// functionAPIWithRegion returns a new container registry API and the region.
Expand Down Expand Up @@ -77,6 +78,20 @@ func waitForFunction(ctx context.Context, functionAPI *function.API, region scw.
return f, err
}

func waitForFunctionCron(ctx context.Context, functionAPI *function.API, region scw.Region, cronID string, timeout time.Duration) (*function.Cron, error) {
retryInterval := defaultFunctionRetryInterval
if DefaultWaitRetryInterval != nil {
retryInterval = *DefaultWaitRetryInterval
}

return functionAPI.WaitForCron(&function.WaitForCronRequest{
Region: region,
CronID: cronID,
RetryInterval: &retryInterval,
Timeout: scw.TimeDurationPtr(timeout),
}, scw.WithContext(ctx))
}

func functionUpload(ctx context.Context, m interface{}, functionAPI *function.API, region scw.Region, functionID string, zipFile string) error {
meta := m.(*Meta)
zipStat, err := os.Stat(zipFile)
Expand Down
1 change: 1 addition & 0 deletions scaleway/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
"scaleway_domain_zone": resourceScalewayDomainZone(),
"scaleway_flexible_ip": resourceScalewayFlexibleIP(),
"scaleway_function": resourceScalewayFunction(),
"scaleway_function_cron": resourceScalewayFunctionCron(),
"scaleway_function_namespace": resourceScalewayFunctionNamespace(),
"scaleway_instance_image": resourceScalewayInstanceImage(),
"scaleway_instance_ip": resourceScalewayInstanceIP(),
Expand Down
192 changes: 192 additions & 0 deletions scaleway/resource_function_cron.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package scaleway

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
function "github.com/scaleway/scaleway-sdk-go/api/function/v1beta1"
"github.com/scaleway/scaleway-sdk-go/scw"
)

func resourceScalewayFunctionCron() *schema.Resource {
return &schema.Resource{
CreateContext: resourceScalewayFunctionCronCreate,
ReadContext: resourceScalewayFunctionCronRead,
UpdateContext: resourceScalewayFunctionCronUpdate,
DeleteContext: resourceScalewayFunctionCronDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Default: schema.DefaultTimeout(defaultFunctionCronTimeout),
Read: schema.DefaultTimeout(defaultFunctionCronTimeout),
Update: schema.DefaultTimeout(defaultFunctionCronTimeout),
Delete: schema.DefaultTimeout(defaultFunctionCronTimeout),
Create: schema.DefaultTimeout(defaultFunctionCronTimeout),
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"function_id": {
Type: schema.TypeString,
Description: "The ID of the function to create a cron for.",
Required: true,
},
"schedule": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateCronExpression(),
Description: "Cron format string, e.g. 0 * * * * or @hourly, as schedule time of its jobs to be created and executed.",
},
"args": {
Type: schema.TypeString,
Required: true,
Description: "Functions arguments as json object to pass through during execution.",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Cron job status.",
},
"region": regionSchema(),
},
}
}

func resourceScalewayFunctionCronCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
api, region, err := functionAPIWithRegion(d, meta)
if err != nil {
return diag.FromErr(err)
}

functionID := expandID(d.Get("function_id").(string))
f, err := waitForFunction(ctx, api, region, functionID, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.FromErr(err)
}

request := &function.CreateCronRequest{
FunctionID: f.ID,
Schedule: d.Get("schedule").(string),
Region: region,
}

if args, ok := d.GetOk("args"); ok {
jsonObj, err := scw.DecodeJSONObject(args.(string), scw.NoEscape)
if err != nil {
return diag.FromErr(err)
}
request.Args = &jsonObj
}

cron, err := api.CreateCron(request, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

_, err = waitForFunctionCron(ctx, api, region, cron.ID, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.FromErr(err)
}

d.SetId(newRegionalIDString(region, cron.ID))

return resourceScalewayFunctionCronRead(ctx, d, meta)
}

func resourceScalewayFunctionCronRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutRead))
if err != nil {
if is404Error(err) {
d.SetId("")
return nil
}
return diag.FromErr(err)
}

_ = d.Set("function_id", newRegionalID(region, cron.FunctionID).String())
_ = d.Set("schedule", cron.Schedule)

args, err := scw.EncodeJSONObject(*cron.Args, scw.NoEscape)
if err != nil {
return diag.FromErr(err)
}

_ = d.Set("args", args)
_ = d.Set("status", cron.Status)

return nil
}

func resourceScalewayFunctionCronUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(err)
}

req := &function.UpdateCronRequest{
Region: region,
CronID: cron.ID,
}

shouldUpdate := false
if d.HasChange("schedule") {
req.Schedule = expandStringPtr(d.Get("schedule").(string))
shouldUpdate = true
}

if d.HasChange("args") {
jsonObj, err := scw.DecodeJSONObject(d.Get("args").(string), scw.NoEscape)
if err != nil {
return diag.FromErr(err)
}
shouldUpdate = true
req.Args = &jsonObj
}

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

return resourceScalewayFunctionCronRead(ctx, d, meta)
}

func resourceScalewayFunctionCronDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutDelete))
if err != nil {
if is404Error(err) {
d.SetId("")
return nil
}
return diag.FromErr(err)
}

_, err = api.DeleteCron(&function.DeleteCronRequest{
Region: region,
CronID: cron.ID,
}, scw.WithContext(ctx))

if err != nil && !is404Error(err) {
return diag.FromErr(err)
}

return nil
}

0 comments on commit 1cdf057

Please sign in to comment.