Skip to content

Commit

Permalink
feat: add workflow job templates resource (#84)
Browse files Browse the repository at this point in the history
* Add Terraform resource for launching workflow job templates

This commit introduces a new Terraform resource `awx_workflow_job_template_launch` to create, manage, and optionally wait for the completion of workflow job templates via the AWX API.

Closes issue #83

* Fix typos in logs, comments, and descriptions

* fix: update dependencies
  • Loading branch information
cepitacio authored Dec 14, 2024
1 parent dc5a15b commit 6b8e0e3
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 1 deletion.
1 change: 1 addition & 0 deletions awx/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func Provider() *schema.Provider {
"awx_job_template_credential": resourceJobTemplateCredentials(),
"awx_job_template": resourceJobTemplate(),
"awx_job_template_launch": resourceJobTemplateLaunch(),
"awx_workflow_job_template_launch": resourceWorkflowJobTeamplateLaunch(),
"awx_job_template_notification_template_error": resourceJobTemplateNotificationTemplateError(),
"awx_job_template_notification_template_started": resourceJobTemplateNotificationTemplateStarted(),
"awx_job_template_notification_template_success": resourceJobTemplateNotificationTemplateSuccess(),
Expand Down
159 changes: 159 additions & 0 deletions awx/resource_workflow_job_template_launch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
*TBD*
Example Usage
```hcl
resource "awx_workflow_job_template_launch" "now" {
workflow_job_template_id = someid
wait_for_completion = true
}
```
*/

package awx

import (
"context"
"encoding/json"
"fmt"
"log"
"strconv"
"time"

awx "github.com/denouche/goawx/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceWorkflowJobTeamplateLaunch() *schema.Resource {
return &schema.Resource{
CreateContext: resourceWorkflowJobTeamplateLaunchCreate,
ReadContext: resourceWorkflowJobRead,
DeleteContext: resourceWorkflowJobDelete,

Schema: map[string]*schema.Schema{
"workflow_job_template_id": {
Type: schema.TypeInt,
Required: true,
Description: "Workflow job template ID",
ForceNew: true,
},
"extra_vars": {
Type: schema.TypeString,
Optional: true,
Description: "Override workflow job template variables. YAML or JSON values are supported.",
ForceNew: true,
StateFunc: normalizeJsonYaml,
},
"wait_for_completion": {
Type: schema.TypeBool,
Required: false,
Optional: true,
Default: false,
Description: "Resource creation will wait for workflow job completion.",
ForceNew: true,
},
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(20 * time.Minute),
},
}
}

func statusInstanceWorkflowState(ctx context.Context, svc *awx.WorkflowJobService, id int) retry.StateRefreshFunc {
return func() (interface{}, string, error) {

output, err := svc.GetWorkflowJob(id, map[string]string{})

return output, output.Status, err
}
}

func workflowJobTemplateLaunchWait(ctx context.Context, svc *awx.WorkflowJobService, job *awx.JobLaunch, timeout time.Duration) error {

stateConf := &retry.StateChangeConf{
Pending: []string{"new", "pending", "waiting", "running"},
Target: []string{"successful"},
Refresh: statusInstanceWorkflowState(ctx, svc, job.ID),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err := stateConf.WaitForStateContext(ctx)

return err
}

// WorkflokJobTemplateLaunchData provides payload data used by the WorkflowJobTemplateLaunch method
type WorkflokJobTemplateLaunchData struct {
ExtraVars string `json:"extra_vars,omitempty"`
}

func resourceWorkflowJobTeamplateLaunchCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
client := m.(*awx.AWX)
awxService := client.WorkflowJobTemplateService
awxWorkflowJobService := client.WorkflowJobService

workflowJobTemplateID := d.Get("workflow_job_template_id").(int)
_, err := awxService.GetWorkflowJobTemplateByID(workflowJobTemplateID, make(map[string]string))
if err != nil {
return buildDiagNotFoundFail("Workflow job template", workflowJobTemplateID, err)
}

data := WorkflokJobTemplateLaunchData{
ExtraVars: d.Get("extra_vars").(string),
}

var iData map[string]interface{}
idata, _ := json.Marshal(data)
json.Unmarshal(idata, &iData)

res, err := awxService.Launch(workflowJobTemplateID, iData, map[string]string{})
if err != nil {
log.Printf("Failed to create Workflow Template Launch %v", err)
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Unable to create workflowJobTemplate",
Detail: fmt.Sprintf("WorkflowJobTemplateLaunch with template ID %d, failed to create %s", d.Get("workflow_job_template_id").(int), err.Error()),
})
return diags
}

// return resourceWorkflowJobRead(ctx, d, m)
d.SetId(strconv.Itoa(res.ID))
if d.Get("wait_for_completion").(bool) { // Print the full structure of the result object
err = workflowJobTemplateLaunchWait(ctx, awxWorkflowJobService, res, d.Timeout(schema.TimeoutCreate))
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "WorkflowJobTemplate execution failure",
Detail: fmt.Sprintf("WorkflowJobTemplateLaunch with ID %d and Workflow template ID %d, failed to complete %s", res.ID, d.Get("workflow_job_template_id").(int), err.Error()),
})
}
}
return diags
}

func resourceWorkflowJobRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
return diags
}

func resourceWorkflowJobDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var diags diag.Diagnostics
client := m.(*awx.AWX)
awxService := client.WorkflowJobService
jobID, diags := convertStateIDToNummeric("Delete Workflow Job", d)
_, err := awxService.GetWorkflowJob(jobID, map[string]string{})
if err != nil {
return buildDiagNotFoundFail("Workflow job", jobID, err)
}

d.SetId("")
return diags
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/denouche/terraform-provider-awx
go 1.20

require (
github.com/denouche/goawx v0.21.1
github.com/denouche/goawx v0.22.0
github.com/gruntwork-io/terratest v0.31.2
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0
github.com/stretchr/testify v1.8.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ github.com/denouche/goawx v0.20.1 h1:Mnkk1QxGPBvo3U4FDhcdHFrSMwIT+IwAkLDVQ7dCAoc
github.com/denouche/goawx v0.20.1/go.mod h1:MppzSteoj2xgfiqiRWW/Bf1a8z2FrRyvah1z0J2vJTY=
github.com/denouche/goawx v0.21.1 h1:ImTBH6/L3u8QInlPHMWO02su4lQPHudj52ZvwKeL86A=
github.com/denouche/goawx v0.21.1/go.mod h1:Bdo/LeUgeemE9Xt4bOVFVO6GJMxxUcduhQPDD5+yQ1A=
github.com/denouche/goawx v0.22.0 h1:P5ReudHwkBNrfiK2jbY10U0uFxCNyvEpw4x9u3wAcq0=
github.com/denouche/goawx v0.22.0/go.mod h1:Bdo/LeUgeemE9Xt4bOVFVO6GJMxxUcduhQPDD5+yQ1A=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
Expand Down

0 comments on commit 6b8e0e3

Please sign in to comment.