From 3b481b93e2ecb92d55f8c7714d9e5ef72f65a5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilson=20J=C3=BAnior?= Date: Fri, 22 Mar 2024 15:00:48 -0300 Subject: [PATCH] Fix use of active_deadline_seconds and concurrency_policy --- docs/resources/job.md | 14 +- go.mod | 2 +- go.sum | 6 +- internal/provider/resource_tsuru_job.go | 65 +++++----- internal/provider/resource_tsuru_job_test.go | 129 +++++++++++++++++++ 5 files changed, 169 insertions(+), 47 deletions(-) diff --git a/docs/resources/job.md b/docs/resources/job.md index 952c0a5..9ddff33 100644 --- a/docs/resources/job.md +++ b/docs/resources/job.md @@ -41,10 +41,11 @@ resource "tsuru_job" "my-job" { ### Optional +- `active_deadline_seconds` (Number) Time a Job can run before its terminated. Defaults is 3600 +- `concurrency_policy` (String) Concurrency policy - `description` (String) Job description - `metadata` (Block List, Max: 1) (see [below for nested schema](#nestedblock--metadata)) - `schedule` (String) Cron-like schedule for when the job should be triggered -- `spec` (Block List, Max: 1) Check Kubernetes official Job specs docs for more details (see [below for nested schema](#nestedblock--spec)) - `tags` (List of String) Tags - `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) @@ -73,17 +74,6 @@ Optional: - `labels` (Map of String) - -### Nested Schema for `spec` - -Optional: - -- `active_deadline_seconds` (Number) Time a Job can run before its terminated. Has precedence over backoff_limit. Defaults to no deadline -- `backoff_limit` (Number) Number of retries before considering a Job as failed. Default=6 -- `completions` (Number) Successful executions for the job to be consider done. Default=1 -- `parallelism` (Number) Number of concurrent instances (Pods) of the job. Default=1 - - ### Nested Schema for `timeouts` diff --git a/go.mod b/go.mod index dfb7ae6..0897c11 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/labstack/echo/v4 v4.9.1 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 - github.com/tsuru/go-tsuruclient v0.0.0-20231130165047-4fa4c756fc6d + github.com/tsuru/go-tsuruclient v0.0.0-20240322174439-2a0eecb27288 github.com/tsuru/tsuru v0.0.0-20230721211340-f41fb455f8c3 k8s.io/apimachinery v0.22.5 ) diff --git a/go.sum b/go.sum index 426c390..09bb047 100644 --- a/go.sum +++ b/go.sum @@ -298,10 +298,8 @@ github.com/tsuru/config v0.0.0-20201023175036-375aaee8b560 h1:fniQ/BmYAHdnNmY333 github.com/tsuru/config v0.0.0-20201023175036-375aaee8b560/go.mod h1:mj6t8JKWU51GScTT50XRmDj65T5XhTyNvO5FUNV5zS4= github.com/tsuru/gnuflag v0.0.0-20151217162021-86b8c1b864aa h1:JlLQP1xa13a994p/Aau2e3K9xXYaHNoNvTDVIMHSUa4= github.com/tsuru/gnuflag v0.0.0-20151217162021-86b8c1b864aa/go.mod h1:UibOSvkMFKRe/eiwktAPAvQG8L+p8nYsECJvu3Dgw7I= -github.com/tsuru/go-tsuruclient v0.0.0-20231108180105-5735487e6f98 h1:bjSRngH503mFLCj/1EyVxR62OF6huYMkR903VIa23BM= -github.com/tsuru/go-tsuruclient v0.0.0-20231108180105-5735487e6f98/go.mod h1:BmePxHey9hxrxk0kzTMHFFr7aJWXSxtlrUx6FIeV0Ic= -github.com/tsuru/go-tsuruclient v0.0.0-20231130165047-4fa4c756fc6d h1:oP+/hghDjbLlfka1U/IDBi9sKWdrHcb/QOYLuvxkU14= -github.com/tsuru/go-tsuruclient v0.0.0-20231130165047-4fa4c756fc6d/go.mod h1:BmePxHey9hxrxk0kzTMHFFr7aJWXSxtlrUx6FIeV0Ic= +github.com/tsuru/go-tsuruclient v0.0.0-20240322174439-2a0eecb27288 h1:v8yGiRYcPL+85UwXpHlmCZ9Nz/Z2utxoAtBYtrnCzY8= +github.com/tsuru/go-tsuruclient v0.0.0-20240322174439-2a0eecb27288/go.mod h1:BmePxHey9hxrxk0kzTMHFFr7aJWXSxtlrUx6FIeV0Ic= github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6 h1:1XDdWFAjIbCSG1OjN9v9KdWhuM8UtYlFcfHe/Ldkchk= github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6/go.mod h1:ztYpOhW+u1k21FEqp7nZNgpWbr0dUKok5lgGCZi+1AQ= github.com/tsuru/tsuru v0.0.0-20230721211340-f41fb455f8c3 h1:Fi5mEiJiHlTCaSYpfP19kbiOzJD26yqwVojUKdLsVHA= diff --git a/internal/provider/resource_tsuru_job.go b/internal/provider/resource_tsuru_job.go index 59cd3b6..a5d3d8f 100644 --- a/internal/provider/resource_tsuru_job.go +++ b/internal/provider/resource_tsuru_job.go @@ -113,38 +113,16 @@ func resourceTsuruJob() *schema.Resource { }, }, - "spec": { - Type: schema.TypeList, - Description: "Check Kubernetes official Job specs docs for more details", - MaxItems: 1, + "active_deadline_seconds": { + Type: schema.TypeInt, + Description: "Time a Job can run before its terminated. Defaults is 3600", Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "completions": { - Type: schema.TypeInt, - Description: "Successful executions for the job to be consider done. Default=1", - Optional: true, - }, - - "parallelism": { - Type: schema.TypeInt, - Description: "Number of concurrent instances (Pods) of the job. Default=1", - Optional: true, - }, - - "active_deadline_seconds": { - Type: schema.TypeInt, - Description: "Time a Job can run before its terminated. Has precedence over backoff_limit. Defaults to no deadline", - Optional: true, - }, + }, - "backoff_limit": { - Type: schema.TypeInt, - Description: "Number of retries before considering a Job as failed. Default=6", - Optional: true, - }, - }, - }, + "concurrency_policy": { + Type: schema.TypeString, + Description: "Concurrency policy", + Optional: true, }, }, } @@ -238,6 +216,10 @@ func resourceTsuruJobRead(ctx context.Context, d *schema.ResourceData, meta inte d.Set("description", job.Job.Description) } + for key, value := range flattenJobSpec(job.Job.Spec) { + d.Set(key, value) + } + d.Set("metadata", flattenMetadata(job.Job.Metadata)) return nil @@ -327,6 +309,15 @@ func inputJobFromResourceData(ctx context.Context, d *schema.ResourceData, provi if schedule, ok := d.GetOk("schedule"); ok { job.Schedule = schedule.(string) } + if concurrencyPolicyInterface, ok := d.GetOk("concurrency_policy"); ok { + concurrencyPolicy := concurrencyPolicyInterface.(string) + job.ConcurrencyPolicy = &concurrencyPolicy + } + + if activeDeadLineSecondsInterface, ok := d.GetOk("active_deadline_seconds"); ok { + activeDeadLineSeconds := int64(activeDeadLineSecondsInterface.(int)) + job.ActiveDeadlineSeconds = &activeDeadLineSeconds + } return job, nil } @@ -363,3 +354,17 @@ func flattenJobContainer(container tsuru.InputJobContainer) []interface{} { return []interface{}{m} } + +func flattenJobSpec(spec tsuru.JobSpec) map[string]any { + m := map[string]any{} + + if spec.ConcurrencyPolicy != nil { + m["concurrency_policy"] = spec.ConcurrencyPolicy + } + + if spec.ActiveDeadlineSeconds != nil { + m["active_deadline_seconds"] = *spec.ActiveDeadlineSeconds + } + + return m +} diff --git a/internal/provider/resource_tsuru_job_test.go b/internal/provider/resource_tsuru_job_test.go index df463d6..f4a1964 100644 --- a/internal/provider/resource_tsuru_job_test.go +++ b/internal/provider/resource_tsuru_job_test.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" echo "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tsuru/go-tsuruclient/pkg/tsuru" ) @@ -113,6 +114,113 @@ func TestAccResourceTsuruJob(t *testing.T) { }) } +func TestAccResourceTsuruJobComplete(t *testing.T) { + fakeServer := echo.New() + + iterationCount := 0 + + fakeServer.GET("/1.0/pools", func(c echo.Context) error { + return c.JSON(http.StatusOK, []tsuru.Pool{{Name: "prod"}}) + }) + + fakeServer.GET("/1.0/plans", func(c echo.Context) error { + return c.JSON(http.StatusOK, []tsuru.Plan{{Name: "c1m1"}}) + }) + + fakeServer.POST("/1.13/jobs", func(c echo.Context) error { + job := tsuru.InputJob{} + c.Bind(&job) + assert.Equal(t, "job01", job.Name) + assert.Equal(t, "my job description", job.Description) + assert.Equal(t, "c1m1", job.Plan) + assert.Equal(t, "my-team", job.TeamOwner) + assert.Equal(t, "prod", job.Pool) + assert.Equal(t, []string{"sleep", "600"}, job.Container.Command) + assert.Equal(t, "tsuru/scratch:latest", job.Container.Image) + require.NotNil(t, job.ConcurrencyPolicy) + assert.Equal(t, "Forbid", *job.ConcurrencyPolicy) + + require.NotNil(t, job.ActiveDeadlineSeconds) + assert.Equal(t, int64(300), *job.ActiveDeadlineSeconds) + + iterationCount++ + return c.JSON(http.StatusOK, map[string]interface{}{ + "status": "success", + "jobName": job.Name, + }) + }) + + fakeServer.GET("/1.13/jobs/:name", func(c echo.Context) error { + name := c.Param("name") + if name != "job01" { + return nil + } + + concurrencyPolicy := "Forbid" + activeDeadLineSeconds := int64(300) + + if iterationCount == 1 { + job := &tsuru.Job{ + Name: name, + Description: "my job description", + TeamOwner: "my-team", + Plan: tsuru.Plan{Name: "c1m1"}, + Pool: "prod", + Spec: tsuru.JobSpec{ + Container: tsuru.InputJobContainer{ + Image: "tsuru/scratch:latest", + Command: []string{ + "sleep", + "600", + }, + }, + ConcurrencyPolicy: &concurrencyPolicy, + ActiveDeadlineSeconds: &activeDeadLineSeconds, + }, + } + return c.JSON(http.StatusOK, tsuru.JobInfo{Job: *job}) + } + + return c.JSON(http.StatusNotFound, nil) + }) + + fakeServer.PUT("/1.13/jobs/:name", func(c echo.Context) error { + return c.JSON(http.StatusOK, nil) + }) + + fakeServer.DELETE("/1.13/jobs/:name", func(c echo.Context) error { + name := c.Param("name") + assert.Equal(t, "job01", name) + return c.NoContent(http.StatusNoContent) + }) + + fakeServer.HTTPErrorHandler = func(err error, c echo.Context) { + t.Errorf("methods=%s, path=%s, err=%s", c.Request().Method, c.Path(), err.Error()) + } + server := httptest.NewServer(fakeServer) + os.Setenv("TSURU_TARGET", server.URL) + + resourceName := "tsuru_job.job" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccResourceTsuruJob_complete(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", "job01"), + resource.TestCheckResourceAttr(resourceName, "description", "my job description"), + resource.TestCheckResourceAttr(resourceName, "plan", "c1m1"), + resource.TestCheckResourceAttr(resourceName, "team_owner", "my-team"), + resource.TestCheckResourceAttr(resourceName, "pool", "prod"), + ), + }, + }, + }) +} + func testAccResourceTsuruJob_basic() string { return ` resource "tsuru_job" "job" { @@ -129,3 +237,24 @@ func testAccResourceTsuruJob_basic() string { } ` } + +func testAccResourceTsuruJob_complete() string { + return ` + resource "tsuru_job" "job" { + name = "job01" + description = "my job description" + plan = "c1m1" + team_owner = "my-team" + pool = "prod" + schedule = "* * * * *" + container { + image = "tsuru/scratch:latest" + command = ["sleep", 600] + } + + + active_deadline_seconds = 300 + concurrency_policy = "Forbid" + } +` +}