Skip to content

Commit be9e0cd

Browse files
DavidGOrtegarestyled-io[bot]restyled-commitscasperdcl
authored
Task directory_out (#340)
* Task directory_out * UpdateContext * integration * nested storage * remove integrations * Restyled by gofmt (#346) Co-authored-by: Restyled.io <[email protected]> * directory_out must be empty or not exists * Restyled by gofmt (#351) Co-authored-by: Restyled.io <[email protected]> * workdir * docs: workdir * docs: minify HCL syntax Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com> Co-authored-by: Restyled.io <[email protected]> Co-authored-by: Casper da Costa-Luis <[email protected]>
1 parent caa45bb commit be9e0cd

File tree

10 files changed

+96
-53
lines changed

10 files changed

+96
-53
lines changed

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,9 @@ Create a file named `main.tf` in an empty directory with the following contents:
9090

9191
```hcl
9292
terraform {
93-
required_providers {
94-
iterative = {
95-
source = "github.com/iterative/iterative"
96-
}
97-
}
93+
required_providers { iterative = { source = "iterative/iterative" } }
9894
}
99-
10095
provider "iterative" {}
101-
10296
# ... other resource blocks ...
10397
```
10498

docs/guides/getting-started.md

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,16 @@ In the project root directory:
1515

1616
```hcl
1717
terraform {
18-
required_providers {
19-
iterative = {
20-
source = "iterative/iterative"
21-
}
22-
}
18+
required_providers { iterative = { source = "iterative/iterative" } }
2319
}
24-
2520
provider "iterative" {}
26-
27-
resource "iterative_task" "example" {
21+
resource "iterative_task" "task" {
2822
name = "example"
2923
cloud = "aws" # or any of: gcp, az, k8s
30-
31-
directory = "${path.root}/shared"
32-
script = <<-END
24+
workdir {
25+
input = "${path.root}/shared"
26+
}
27+
script = <<-END
3328
#!/bin/bash
3429
echo "Hello World!" > greeting.txt
3530
END
@@ -70,7 +65,7 @@ $ terraform apply
7065
This command will:
7166

7267
1. Create all the required cloud resources.
73-
2. Upload the specified shared `directory` to the cloud.
68+
2. Upload the specified shared `input` working directory to the cloud.
7469
3. Launch the task `script`.
7570

7671
## Viewing Task Statuses
@@ -95,7 +90,7 @@ $ terraform destroy
9590

9691
This command will:
9792

98-
1. Download the specified shared `directory` from the cloud.
93+
1. Download the specified shared working directory from the cloud.
9994
2. Delete all the cloud resources created by `terraform apply`.
10095

10196
## Viewing Task Results

docs/index.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,9 @@ Use the Iterative Provider to launch resource-intensive tasks in popular cloud p
66

77
```hcl
88
terraform {
9-
required_providers {
10-
iterative = {
11-
source = "iterative/iterative"
12-
}
13-
}
9+
required_providers { iterative = { source = "iterative/iterative" } }
1410
}
15-
1611
provider "iterative" {}
17-
1812
resource "iterative_task" "task" {
1913
name = "example"
2014
cloud = "aws"

docs/resources/task.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
This resource will:
44

55
1. Create cloud resources (machines and storage) for the task.
6-
2. Upload the given `directory` to the cloud storage, if specified.
7-
3. Run the given `script` until completion or `timeout` in the cloud machine.
6+
2. Upload the given `workdir.input` to the cloud storage.
7+
3. Run the given `script` on the cloud machine until completion or `timeout`.
8+
4. Download results to the given `workdir.output`.
89

910
## Example Usage
1011

@@ -14,8 +15,11 @@ resource "iterative_task" "task" {
1415
cloud = "aws"
1516
1617
environment = { GREETING = "Hello, world!" }
17-
directory = "${path.root}/shared"
18-
script = <<-END
18+
workdir {
19+
input = "${path.root}/shared"
20+
output = "${path.root}/results"
21+
}
22+
script = <<-END
1923
#!/bin/bash
2024
echo "$GREETING" | tee $(uuidgen)
2125
END
@@ -38,7 +42,8 @@ resource "iterative_task" "task" {
3842
- `spot` - (Optional) Spot instance price. `-1`: disabled, `0`: automatic price, any other positive number: fixed price.
3943
- `image` - (Optional) [Machine image](#machine-images) to run the task with.
4044
- `parallelism` - (Optional) Number of machines to be launched in parallel.
41-
- `directory` - (Optional) Local directory to synchronize.
45+
- `workdir.input` - (Optional) Local working directory to upload.
46+
- `workdir.output` - (Optional) Local directory to download results to (default: `workdir.input`).
4247
- `environment` - (Optional) Map of environment variable names and values for the task script. Empty string values are replaced with local environment values. Empty values may also be combined with a [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) name to import all matching variables.
4348
- `timeout` - (Optional) Maximum number of seconds to run before termination.
4449

@@ -205,7 +210,7 @@ Setting the `region` attribute results in undefined behaviour.
205210

206211
#### Directory storage
207212

208-
Unlike public cloud providers, Kubernetes does not offer any portable way of persisting and sharing storage between pods. When specified, the `directory` attribute will create a `PersistentVolumeClaim` of the default `StorageClass`, with the same lifecycle as the task and the specified `disk_size`.
213+
Unlike public cloud providers, Kubernetes does not offer any portable way of persisting and sharing storage between pods. When specified, the `workdir.input` attribute will create a `PersistentVolumeClaim` of the default `StorageClass`, with the same lifecycle as the task and the specified `disk_size`.
209214

210215
~> **Warning:** Access mode will be `ReadWriteOnce` if `parallelism=1` or `ReadWriteMany` otherwise.
211216

iterative/resource_task.go

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"io"
8+
"os"
79
"strings"
810
"time"
911

@@ -19,6 +21,7 @@ func resourceTask() *schema.Resource {
1921
CreateContext: resourceTaskCreate,
2022
DeleteContext: resourceTaskDelete,
2123
ReadContext: resourceTaskRead,
24+
UpdateContext: resourceTaskRead,
2225
Schema: map[string]*schema.Schema{
2326
"name": {
2427
Type: schema.TypeString,
@@ -103,11 +106,25 @@ func resourceTask() *schema.Resource {
103106
ForceNew: true,
104107
Required: true,
105108
},
106-
"directory": {
107-
Type: schema.TypeString,
108-
ForceNew: true,
109+
"workdir": {
109110
Optional: true,
110-
Default: "",
111+
Type: schema.TypeSet,
112+
Elem: &schema.Resource{
113+
Schema: map[string]*schema.Schema{
114+
"input": {
115+
Type: schema.TypeString,
116+
ForceNew: true,
117+
Optional: true,
118+
Default: "",
119+
},
120+
"output": {
121+
Type: schema.TypeString,
122+
ForceNew: false,
123+
Optional: true,
124+
Default: "",
125+
},
126+
},
127+
},
111128
},
112129
"parallelism": {
113130
Type: schema.TypeInt,
@@ -260,17 +277,34 @@ func resourceTaskBuild(ctx context.Context, d *schema.ResourceData, m interface{
260277
},
261278
}
262279

280+
directory := ""
281+
directory_out := ""
282+
if d.Get("workdir").(*schema.Set).Len() > 0 {
283+
storage := d.Get("workdir").(*schema.Set).List()[0].(map[string]interface{})
284+
directory = storage["input"].(string)
285+
286+
directory_out = storage["output"].(string)
287+
if directory_out == "" {
288+
directory_out = directory
289+
}
290+
}
291+
292+
if directory_out != "" && !isOutputValid(directory_out) {
293+
return nil, errors.New("output directory " + directory_out + " is not empty!")
294+
}
295+
263296
t := common.Task{
264297
Size: common.Size{
265298
Machine: d.Get("machine").(string),
266299
Storage: d.Get("disk_size").(int),
267300
},
268301
Environment: common.Environment{
269-
Image: d.Get("image").(string),
270-
Script: d.Get("script").(string),
271-
Variables: v,
272-
Directory: d.Get("directory").(string),
273-
Timeout: time.Duration(d.Get("timeout").(int)) * time.Second,
302+
Image: d.Get("image").(string),
303+
Script: d.Get("script").(string),
304+
Variables: v,
305+
Directory: directory,
306+
DirectoryOut: directory_out,
307+
Timeout: time.Duration(d.Get("timeout").(int)) * time.Second,
274308
},
275309
Firewall: common.Firewall{
276310
Ingress: common.FirewallRule{
@@ -291,3 +325,17 @@ func diagnostic(diags diag.Diagnostics, err error, severity diag.Severity) diag.
291325
Summary: err.Error(),
292326
})
293327
}
328+
329+
func isOutputValid(path string) bool {
330+
f, err := os.Open(path)
331+
if err != nil {
332+
return true
333+
}
334+
defer f.Close()
335+
336+
_, err = f.Readdir(1)
337+
if err == io.EOF {
338+
return true
339+
}
340+
return false
341+
}

task/aws/task.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ func (t *Task) Read(ctx context.Context) error {
195195

196196
func (t *Task) Delete(ctx context.Context) error {
197197
log.Println("[INFO] Downloading Directory...")
198-
if t.Attributes.Environment.Directory != "" && t.Read(ctx) == nil {
199-
if err := t.Pull(ctx, t.Attributes.Environment.Directory); err != nil && err != common.NotFoundError {
198+
if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil {
199+
if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError {
200200
return err
201201
}
202202
}

task/az/task.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ func (t *Task) Read(ctx context.Context) error {
184184

185185
func (t *Task) Delete(ctx context.Context) error {
186186
log.Println("[INFO] Downloading Directory...")
187-
if t.Attributes.Environment.Directory != "" && t.Read(ctx) == nil {
188-
if err := t.Pull(ctx, t.Attributes.Environment.Directory); err != nil && err != common.NotFoundError {
187+
if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil {
188+
if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError {
189189
return err
190190
}
191191
}

task/common/values.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ type Environment struct {
7474
Image string
7575
Script string
7676
Variables
77-
Timeout time.Duration
78-
Directory string
77+
Timeout time.Duration
78+
Directory string
79+
DirectoryOut string
7980
}
8081

8182
type Variables map[string]*string

task/gcp/task.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ func (t *Task) Read(ctx context.Context) error {
263263

264264
func (t *Task) Delete(ctx context.Context) error {
265265
log.Println("[INFO] Downloading Directory...")
266-
if t.Attributes.Environment.Directory != "" && t.Read(ctx) == nil {
267-
if err := t.Pull(ctx, t.Attributes.Environment.Directory); err != nil && err != common.NotFoundError {
266+
if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil {
267+
if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError {
268268
return err
269269
}
270270
}

task/k8s/task.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ func New(ctx context.Context, cloud common.Cloud, identifier common.Identifier,
5353
t.Identifier = identifier
5454
t.Attributes.Task = task
5555
t.Attributes.Directory = persistentVolumeDirectory
56+
t.Attributes.DirectoryOut = persistentVolumeDirectory
57+
if task.Environment.DirectoryOut != "" {
58+
t.Attributes.DirectoryOut = task.Environment.DirectoryOut
59+
}
60+
5661
t.Resources.ConfigMap = resources.NewConfigMap(
5762
t.Client,
5863
t.Identifier,
@@ -80,7 +85,8 @@ type Task struct {
8085
Identifier common.Identifier
8186
Attributes struct {
8287
common.Task
83-
Directory string
88+
Directory string
89+
DirectoryOut string
8490
}
8591
DataSources struct{}
8692
Resources struct {
@@ -156,7 +162,7 @@ func (t *Task) Read(ctx context.Context) error {
156162
}
157163

158164
func (t *Task) Delete(ctx context.Context) error {
159-
if t.Attributes.Directory != "" && t.Read(ctx) == nil {
165+
if t.Attributes.DirectoryOut != "" && t.Read(ctx) == nil {
160166
os.Setenv("TPI_TRANSFER_MODE", "true")
161167
os.Setenv("TPI_PULL_MODE", "true")
162168
defer os.Unsetenv("TPI_TRANSFER_MODE")
@@ -171,7 +177,7 @@ func (t *Task) Delete(ctx context.Context) error {
171177
return err
172178
}
173179
log.Println("[INFO] Downloading Directory...")
174-
if err := t.Pull(ctx, t.Attributes.Directory); err != nil {
180+
if err := t.Pull(ctx, t.Attributes.DirectoryOut); err != nil {
175181
return err
176182
}
177183

0 commit comments

Comments
 (0)