Skip to content

Commit 1cdf057

Browse files
remyleoneMonitob
andauthored
feat(function): add support for cron (#1114)
Co-authored-by: jaime Bernabe <[email protected]>
1 parent aa01160 commit 1cdf057

File tree

7 files changed

+2079
-0
lines changed

7 files changed

+2079
-0
lines changed

docs/resources/function_cron.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
page_title: "Scaleway: scaleway_function_cron"
3+
description: |-
4+
Manages Scaleway Functions Triggers.
5+
---
6+
7+
# scaleway_function_cron
8+
9+
Creates and manages Scaleway Function Triggers. For the moment, the feature is limited to CRON Schedule (time-based).
10+
11+
For more information consult
12+
the [documentation](https://www.scaleway.com/en/docs/compute/functions/api-cli/fun-uploading-with-serverless-framework/#configuring-events)
13+
.
14+
15+
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/).
16+
17+
For more details about the limitation
18+
check [functions-limitations](https://www.scaleway.com/en/docs/compute/functions/reference-content/functions-limitations/).
19+
20+
You can check also
21+
our [functions cron api documentation](https://developers.scaleway.com/en/products/functions/api/#crons-942bf4).
22+
23+
## Example Usage
24+
25+
```hcl
26+
resource scaleway_function_namespace main {
27+
name = "test-cron"
28+
}
29+
30+
resource scaleway_function main {
31+
name = "test-cron"
32+
namespace_id = scaleway_function_namespace.main.id
33+
runtime = "node14"
34+
privacy = "private"
35+
handler = "handler.handle"
36+
}
37+
38+
resource scaleway_function_cron main {
39+
function_id = scaleway_function.main.id
40+
schedule = "0 0 * * *"
41+
args = jsonencode({test = "scw"})
42+
}
43+
44+
resource scaleway_function_cron func {
45+
function_id = scaleway_function.main.id
46+
schedule = "0 1 * * *"
47+
args = jsonencode({my_var = "terraform"})
48+
}
49+
```
50+
51+
## Arguments Reference
52+
53+
The following arguments are required:
54+
55+
- `schedule` - (Required) Cron format string, e.g. @hourly, as schedule time of its jobs to be created and
56+
executed.
57+
- `function_id` - (Required) The function ID to link with your cron.
58+
- `args` - (Required) The key-value mapping to define arguments that will be passed to your function’s event object
59+
during
60+
61+
## Attributes Reference
62+
63+
In addition to all above arguments, the following attributes are exported:
64+
65+
- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions)
66+
in where the job was created.
67+
- `status` - The cron status.
68+
69+
## Import
70+
71+
Container Cron can be imported using the `{region}/{id}`, e.g.
72+
73+
```bash
74+
$ terraform import scaleway_function_cron.main fr-par/11111111-1111-1111-1111-111111111111
75+
```

scaleway/helpers_function.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const (
1919
defaultFunctionTimeout = 15 * time.Minute
2020
defaultFunctionRetryInterval = 5 * time.Second
2121
defaultFunctionAfterUpdateWait = 1 * time.Second
22+
defaultFunctionCronTimeout = 5 * time.Minute
2223
)
2324

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

81+
func waitForFunctionCron(ctx context.Context, functionAPI *function.API, region scw.Region, cronID string, timeout time.Duration) (*function.Cron, error) {
82+
retryInterval := defaultFunctionRetryInterval
83+
if DefaultWaitRetryInterval != nil {
84+
retryInterval = *DefaultWaitRetryInterval
85+
}
86+
87+
return functionAPI.WaitForCron(&function.WaitForCronRequest{
88+
Region: region,
89+
CronID: cronID,
90+
RetryInterval: &retryInterval,
91+
Timeout: scw.TimeDurationPtr(timeout),
92+
}, scw.WithContext(ctx))
93+
}
94+
8095
func functionUpload(ctx context.Context, m interface{}, functionAPI *function.API, region scw.Region, functionID string, zipFile string) error {
8196
meta := m.(*Meta)
8297
zipStat, err := os.Stat(zipFile)

scaleway/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
105105
"scaleway_domain_zone": resourceScalewayDomainZone(),
106106
"scaleway_flexible_ip": resourceScalewayFlexibleIP(),
107107
"scaleway_function": resourceScalewayFunction(),
108+
"scaleway_function_cron": resourceScalewayFunctionCron(),
108109
"scaleway_function_namespace": resourceScalewayFunctionNamespace(),
109110
"scaleway_instance_image": resourceScalewayInstanceImage(),
110111
"scaleway_instance_ip": resourceScalewayInstanceIP(),

scaleway/resource_function_cron.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
function "github.com/scaleway/scaleway-sdk-go/api/function/v1beta1"
9+
"github.com/scaleway/scaleway-sdk-go/scw"
10+
)
11+
12+
func resourceScalewayFunctionCron() *schema.Resource {
13+
return &schema.Resource{
14+
CreateContext: resourceScalewayFunctionCronCreate,
15+
ReadContext: resourceScalewayFunctionCronRead,
16+
UpdateContext: resourceScalewayFunctionCronUpdate,
17+
DeleteContext: resourceScalewayFunctionCronDelete,
18+
Importer: &schema.ResourceImporter{
19+
StateContext: schema.ImportStatePassthroughContext,
20+
},
21+
Timeouts: &schema.ResourceTimeout{
22+
Default: schema.DefaultTimeout(defaultFunctionCronTimeout),
23+
Read: schema.DefaultTimeout(defaultFunctionCronTimeout),
24+
Update: schema.DefaultTimeout(defaultFunctionCronTimeout),
25+
Delete: schema.DefaultTimeout(defaultFunctionCronTimeout),
26+
Create: schema.DefaultTimeout(defaultFunctionCronTimeout),
27+
},
28+
SchemaVersion: 0,
29+
Schema: map[string]*schema.Schema{
30+
"function_id": {
31+
Type: schema.TypeString,
32+
Description: "The ID of the function to create a cron for.",
33+
Required: true,
34+
},
35+
"schedule": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
ValidateFunc: validateCronExpression(),
39+
Description: "Cron format string, e.g. 0 * * * * or @hourly, as schedule time of its jobs to be created and executed.",
40+
},
41+
"args": {
42+
Type: schema.TypeString,
43+
Required: true,
44+
Description: "Functions arguments as json object to pass through during execution.",
45+
},
46+
"status": {
47+
Type: schema.TypeString,
48+
Computed: true,
49+
Description: "Cron job status.",
50+
},
51+
"region": regionSchema(),
52+
},
53+
}
54+
}
55+
56+
func resourceScalewayFunctionCronCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
57+
api, region, err := functionAPIWithRegion(d, meta)
58+
if err != nil {
59+
return diag.FromErr(err)
60+
}
61+
62+
functionID := expandID(d.Get("function_id").(string))
63+
f, err := waitForFunction(ctx, api, region, functionID, d.Timeout(schema.TimeoutCreate))
64+
if err != nil {
65+
return diag.FromErr(err)
66+
}
67+
68+
request := &function.CreateCronRequest{
69+
FunctionID: f.ID,
70+
Schedule: d.Get("schedule").(string),
71+
Region: region,
72+
}
73+
74+
if args, ok := d.GetOk("args"); ok {
75+
jsonObj, err := scw.DecodeJSONObject(args.(string), scw.NoEscape)
76+
if err != nil {
77+
return diag.FromErr(err)
78+
}
79+
request.Args = &jsonObj
80+
}
81+
82+
cron, err := api.CreateCron(request, scw.WithContext(ctx))
83+
if err != nil {
84+
return diag.FromErr(err)
85+
}
86+
87+
_, err = waitForFunctionCron(ctx, api, region, cron.ID, d.Timeout(schema.TimeoutCreate))
88+
if err != nil {
89+
return diag.FromErr(err)
90+
}
91+
92+
d.SetId(newRegionalIDString(region, cron.ID))
93+
94+
return resourceScalewayFunctionCronRead(ctx, d, meta)
95+
}
96+
97+
func resourceScalewayFunctionCronRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
98+
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
99+
if err != nil {
100+
return diag.FromErr(err)
101+
}
102+
103+
cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutRead))
104+
if err != nil {
105+
if is404Error(err) {
106+
d.SetId("")
107+
return nil
108+
}
109+
return diag.FromErr(err)
110+
}
111+
112+
_ = d.Set("function_id", newRegionalID(region, cron.FunctionID).String())
113+
_ = d.Set("schedule", cron.Schedule)
114+
115+
args, err := scw.EncodeJSONObject(*cron.Args, scw.NoEscape)
116+
if err != nil {
117+
return diag.FromErr(err)
118+
}
119+
120+
_ = d.Set("args", args)
121+
_ = d.Set("status", cron.Status)
122+
123+
return nil
124+
}
125+
126+
func resourceScalewayFunctionCronUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
127+
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
128+
if err != nil {
129+
return diag.FromErr(err)
130+
}
131+
132+
cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutUpdate))
133+
if err != nil {
134+
return diag.FromErr(err)
135+
}
136+
137+
req := &function.UpdateCronRequest{
138+
Region: region,
139+
CronID: cron.ID,
140+
}
141+
142+
shouldUpdate := false
143+
if d.HasChange("schedule") {
144+
req.Schedule = expandStringPtr(d.Get("schedule").(string))
145+
shouldUpdate = true
146+
}
147+
148+
if d.HasChange("args") {
149+
jsonObj, err := scw.DecodeJSONObject(d.Get("args").(string), scw.NoEscape)
150+
if err != nil {
151+
return diag.FromErr(err)
152+
}
153+
shouldUpdate = true
154+
req.Args = &jsonObj
155+
}
156+
157+
if shouldUpdate {
158+
_, err = api.UpdateCron(req, scw.WithContext(ctx))
159+
if err != nil {
160+
return diag.FromErr(err)
161+
}
162+
}
163+
164+
return resourceScalewayFunctionCronRead(ctx, d, meta)
165+
}
166+
167+
func resourceScalewayFunctionCronDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
168+
api, region, id, err := functionAPIWithRegionAndID(meta, d.Id())
169+
if err != nil {
170+
return diag.FromErr(err)
171+
}
172+
173+
cron, err := waitForFunctionCron(ctx, api, region, id, d.Timeout(schema.TimeoutDelete))
174+
if err != nil {
175+
if is404Error(err) {
176+
d.SetId("")
177+
return nil
178+
}
179+
return diag.FromErr(err)
180+
}
181+
182+
_, err = api.DeleteCron(&function.DeleteCronRequest{
183+
Region: region,
184+
CronID: cron.ID,
185+
}, scw.WithContext(ctx))
186+
187+
if err != nil && !is404Error(err) {
188+
return diag.FromErr(err)
189+
}
190+
191+
return nil
192+
}

0 commit comments

Comments
 (0)