From abd7c8d587cc4f1fbf6cf9c54f910b69b28018ff Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Thu, 24 Oct 2019 11:39:51 -0400 Subject: [PATCH 1/7] Add importer and fix typo. --- rundeck/resource_job.go | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/rundeck/resource_job.go b/rundeck/resource_job.go index 7a460cc50a..70051fe4ab 100644 --- a/rundeck/resource_job.go +++ b/rundeck/resource_job.go @@ -16,6 +16,9 @@ func resourceRundeckJob() *schema.Resource { Delete: DeleteJob, Exists: JobExists, Read: ReadJob, + Importer: &schema.ResourceImporter{ + State: resourceJobImport, + }, Schema: map[string]*schema.Schema{ "name": { @@ -239,7 +242,6 @@ func resourceRundeckJob() *schema.Resource { }, }, }, - "command": { Type: schema.TypeList, Required: true, @@ -737,7 +739,7 @@ func jobToResourceData(job *JobDetail, d *schema.ResourceData) error { "value_choices_url": option.ValueChoicesURL, "require_predefined_choice": option.RequirePredefinedChoice, "validation_regex": option.ValidationRegex, - "decription": option.Description, + "description": option.Description, "required": option.IsRequired, "allow_multiple_values": option.AllowsMultipleValues, "multi_value_delimiter": option.MultiValueDelimiter, @@ -860,3 +862,29 @@ func readNotification(notification *Notification, notificationType string) map[s } return notificationConfigI } + +func resourceJobImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + idAttr := strings.SplitN(d.Id(), "/", 2) + var jobID string + var projectName string + + if len(idAttr) == 2 { + projectName = idAttr[0] + jobID = idAttr[1] + } else { + return nil, fmt.Errorf("invalid id %q specified, should be in format \"projectName/JobUUID\" for import", d.Id()) + } + d.SetId(jobID) + + err := ReadJob(d, meta) + if err != nil { + return nil, err + } + // Get the information out of the api if available. + // Otherwise use information supplied by user. + if d.Get("project_name") == "" { + d.Set("project_name", projectName) + } + + return []*schema.ResourceData{d}, nil +} From 3e4754c299c82be590ff9d4c11eae9ff1f45b9ef Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Thu, 24 Oct 2019 11:41:26 -0400 Subject: [PATCH 2/7] Add back newline. --- rundeck/resource_job.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rundeck/resource_job.go b/rundeck/resource_job.go index 70051fe4ab..52a0131fbd 100644 --- a/rundeck/resource_job.go +++ b/rundeck/resource_job.go @@ -242,6 +242,7 @@ func resourceRundeckJob() *schema.Resource { }, }, }, + "command": { Type: schema.TypeList, Required: true, From dc2da7e1735a189fb9681c0a4687a2465aff6c2e Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Thu, 24 Oct 2019 12:57:10 -0400 Subject: [PATCH 3/7] success_on_empty_node_filter was missing in set and value_choices ideompotency had issues. --- rundeck/resource_job.go | 1 + rundeck/resource_job_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rundeck/resource_job.go b/rundeck/resource_job.go index 52a0131fbd..ae15540f02 100644 --- a/rundeck/resource_job.go +++ b/rundeck/resource_job.go @@ -715,6 +715,7 @@ func jobToResourceData(job *JobDetail, d *schema.ResourceData) error { d.Set("continue_on_error", job.Dispatch.ContinueOnError) d.Set("rank_attribute", job.Dispatch.RankAttribute) d.Set("rank_order", job.Dispatch.RankOrder) + d.Set("success_on_empty_node_filter", job.Dispatch.SuccessOnEmptyNodeFilter) } else { d.Set("max_thread_count", 1) d.Set("continue_on_error", nil) diff --git a/rundeck/resource_job_test.go b/rundeck/resource_job_test.go index f23850079d..5a8df6dfad 100644 --- a/rundeck/resource_job_test.go +++ b/rundeck/resource_job_test.go @@ -281,7 +281,7 @@ resource "rundeck_job" "test" { name = "instance_count" default_value = "2" required = "true" - value_choices = ["1,2,3,4,5,6,7,8,9"] + value_choices = ["1","2","3","4","5","6","7","8","9"] require_predefined_choice = "true" } From 91d610d71be10a9cbc1893fc41833ed0f6a9b6e4 Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Thu, 24 Oct 2019 12:57:16 -0400 Subject: [PATCH 4/7] success_on_empty_node_filter was missing in set and value_choices ideompotency had issues. --- rundeck/import_resource_job_test.go | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 rundeck/import_resource_job_test.go diff --git a/rundeck/import_resource_job_test.go b/rundeck/import_resource_job_test.go new file mode 100644 index 0000000000..16f1a38065 --- /dev/null +++ b/rundeck/import_resource_job_test.go @@ -0,0 +1,32 @@ +package rundeck + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccRundeckJob_Import(t *testing.T) { + name := "rundeck_job.test" + project_name := "terraform-acc-test-job" + var job JobDetail + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccJobCheckDestroy(&job), + Steps: []resource.TestStep{ + { + Config: testAccJobConfig_basic, + Check: testAccJobCheckExists(name, &job), + }, + { + ResourceName: name, + ImportStateIdPrefix: fmt.Sprintf("%s/", project_name), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} From 6b6971dd3bd1b64a8dc71d5bae9e7d5f94e08087 Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Fri, 1 Nov 2019 16:19:27 -0400 Subject: [PATCH 5/7] remove excludeprecedence because it causes errors if nodefilters included. --- rundeck/resource_job.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rundeck/resource_job.go b/rundeck/resource_job.go index ae15540f02..3d9992b640 100644 --- a/rundeck/resource_job.go +++ b/rundeck/resource_job.go @@ -472,6 +472,7 @@ func jobFromResourceData(d *schema.ResourceData) (*JobDetail, error) { if len(jobRefsI) > 1 { return nil, fmt.Errorf("rundeck command may have no more than one job") } + if len(jobRefsI) > 0 { jobRefMap := jobRefsI[0].(map[string]interface{}) command.Job = &JobCommandJobRef{ @@ -766,13 +767,19 @@ func jobToResourceData(job *JobDetail, d *schema.ResourceData) error { } if command.Job != nil { + + var nodeFilterMap map[string]interface{} + if command.Job.NodeFilter != nil { + nodeFilterMap = make(map[string]interface{}) + nodeFilterMap["filter"] = command.Job.NodeFilter.Query + } commandConfigI["job"] = []interface{}{ map[string]interface{}{ "name": command.Job.Name, "group_name": command.Job.GroupName, "run_for_each_node": command.Job.RunForEachNode, "args": command.Job.Arguments, - "nodefilters": command.Job.NodeFilter, + "nodefilters": nodeFilterMap, }, } } From 9e86e81e3b6232b3824c8fad14087f5a54357fa4 Mon Sep 17 00:00:00 2001 From: Evan Farrell Date: Thu, 20 Feb 2020 16:52:30 -0500 Subject: [PATCH 6/7] Added website docs for job import. --- website/docs/r/job.html.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/website/docs/r/job.html.md b/website/docs/r/job.html.md index 7cc9bcdf39..6fbc5d6043 100644 --- a/website/docs/r/job.html.md +++ b/website/docs/r/job.html.md @@ -215,3 +215,11 @@ A notification's `plugin` block has the following structure: The following attribute is exported: * `id` - A unique identifier for the job. + +## Import + +Rundeck job can be imported using the project and job uuid, e.g. + +``` +$ terraform import rundeck_job.my_job project_name/JOB-UUID +``` From df87b1a31b106fd6b4edc7d464307ed4fe7472c7 Mon Sep 17 00:00:00 2001 From: Andrea Berlingieri Date: Wed, 26 Jun 2024 15:27:03 +0200 Subject: [PATCH 7/7] Fix Acceptance tests Add timeout and success_on_empty_node_filter to attributes set to the job based on job data (jobToResourceData function) Fix TestOchestrator_high_low and TestOchestrator_max_percent (wrong job name in the expected/actual test) Fix testAccJobOptions_secure_options (shouldn't expect an error, should just check that the right option on the job has been set) --- rundeck/import_resource_job_test.go | 2 +- rundeck/resource_job.go | 6 ++++++ rundeck/resource_job_test.go | 23 +++++++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/rundeck/import_resource_job_test.go b/rundeck/import_resource_job_test.go index 16f1a38065..acd626f19e 100644 --- a/rundeck/import_resource_job_test.go +++ b/rundeck/import_resource_job_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) func TestAccRundeckJob_Import(t *testing.T) { diff --git a/rundeck/resource_job.go b/rundeck/resource_job.go index 95d5e364e8..f4a5e8730e 100644 --- a/rundeck/resource_job.go +++ b/rundeck/resource_job.go @@ -928,6 +928,9 @@ func jobToResourceData(job *JobDetail, d *schema.ResourceData) error { if err := d.Set("allow_concurrent_executions", job.AllowConcurrentExecutions); err != nil { return err } + if err := d.Set("timeout", job.Timeout); err != nil { + return err + } if job.Retry != nil { if err := d.Set("retry", job.Retry.Value); err != nil { return err @@ -949,6 +952,9 @@ func jobToResourceData(job *JobDetail, d *schema.ResourceData) error { if err := d.Set("rank_order", job.Dispatch.RankOrder); err != nil { return err } + if err := d.Set("success_on_empty_node_filter", job.Dispatch.SuccessOnEmptyNodeFilter); err != nil { + return err + } } else { if err := d.Set("max_thread_count", 1); err != nil { return err diff --git a/rundeck/resource_job_test.go b/rundeck/resource_job_test.go index 20fec04586..da647a05f7 100644 --- a/rundeck/resource_job_test.go +++ b/rundeck/resource_job_test.go @@ -83,7 +83,7 @@ func TestOchestrator_high_low(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccJobCheckExists("rundeck_job.test", &job), func(s *terraform.State) error { - if expected := "basic-job-with-node-filter"; job.Name != expected { + if expected := "orchestrator-High-Low"; job.Name != expected { return fmt.Errorf("wrong name; expected %v, got %v", expected, job.Name) } if expected := "name: tacobell"; job.CommandSequence.Commands[0].Job.NodeFilter.Query != expected { @@ -110,7 +110,7 @@ func TestOchestrator_max_percent(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccJobCheckExists("rundeck_job.test", &job), func(s *terraform.State) error { - if expected := "basic-job-with-node-filter"; job.Name != expected { + if expected := "orchestrator-MaxPercent"; job.Name != expected { return fmt.Errorf("wrong name; expected %v, got %v", expected, job.Name) } if expected := "name: tacobell"; job.CommandSequence.Commands[0].Job.NodeFilter.Query != expected { @@ -261,8 +261,23 @@ func TestAccJobOptions_secure_choice(t *testing.T) { CheckDestroy: testAccJobCheckDestroy(&job), Steps: []resource.TestStep{ { - Config: testAccJobOptions_secure_options, - ExpectError: regexp.MustCompile("argument \"value_choices\" can not have empty values; try \"required\""), + Config: testAccJobOptions_secure_options, + Check: resource.ComposeTestCheckFunc( + testAccJobCheckExists("rundeck_job.test", &job), + func(s *terraform.State) error { + secureOption := job.OptionsConfig.Options[0] + if expected := "foo_secure"; secureOption.Name != expected { + return fmt.Errorf("wrong name; expected %v, got %v", expected, secureOption.Name) + } + if expected := "/keys/test/path/"; secureOption.StoragePath != expected { + return fmt.Errorf("wrong storage_path; expected %v, got %v", expected, secureOption.Name) + } + if expected := true; secureOption.ObscureInput != expected { + return fmt.Errorf("failed to set the input as obscure; expected %v, got %v", expected, secureOption.ObscureInput) + } + return nil + }, + ), }, }, })