├── .github ├── release-drafter.yml ├── dependabot.yml ├── workflows │ ├── release-drafter.yml │ ├── gorelease.yaml │ └── cicd-build.yml └── gorelease.yaml ├── examples ├── k8s │ ├── base │ │ ├── versions.tf │ │ ├── provider.tf │ │ ├── files │ │ │ ├── id_rsa.pub │ │ │ └── id_rsa │ │ └── main.tf │ └── data │ │ ├── versions.tf │ │ ├── provider.tf │ │ └── main.tf └── awx │ └── main.tf ├── tools ├── mage.go ├── go.mod ├── magefile.go ├── installAwx.sh ├── template.go └── docs.go ├── awx ├── convert_type.go ├── resource_workflow_job_template_node_allways.go ├── resource_workflow_job_template_node_failure.go ├── resource_workflow_job_template_node_success.go ├── data_source_credential.go ├── data_source_project.go ├── data_source_organization.go ├── data_source_credentials.go ├── data_source_inventory_group.go ├── data_source_credential_azure_key_vault.go ├── data_source_inventory.go ├── data_source_job_template.go ├── data_source_workflow_job_template.go ├── resource_job_template_credential.go ├── shared_workflow_job_template_node.go ├── provider.go ├── resource_inventory_group.go ├── helpers.go ├── resource_credential_google_compute_engine.go ├── resource_credential_azure_key_vault.go ├── resource_inventory.go ├── resource_credential_scm.go ├── resource_credential_input_source.go ├── resource_organization.go ├── resource_inventory_source.go ├── resource_host.go ├── resource_credential_machine.go ├── resource_workflow_job_template.go ├── resource_project.go ├── resource_workflow_job_template_node.go └── resource_job_template.go ├── main.go ├── docs ├── index.md ├── data-sources │ ├── project.md │ ├── job_template.md │ ├── organization.md │ ├── workflow_job_template.md │ ├── inventory.md │ ├── inventory_group.md │ ├── credentials.md │ ├── credential.md │ └── credential_azure_key_vault.md └── resources │ ├── inventory_group.md │ ├── credential_input_source.md │ ├── credential_scm.md │ ├── credential_azure_key_vault.md │ ├── job_template_credential.md │ ├── inventory_source.md │ ├── organization.md │ ├── credential_machine.md │ ├── inventory.md │ ├── host.md │ ├── workflow_job_template_node.md │ ├── workflow_job_template_node_allways.md │ ├── workflow_job_template_node_failure.md │ ├── workflow_job_template_node_success.md │ ├── workflow_job_template.md │ ├── project.md │ └── job_template.md ├── go.mod ├── .vscode └── launch.json ├── .editorconfig ├── .devcontainer ├── docker-compose.yml ├── Dockerfile └── devcontainer.json ├── test └── terraform_minimal_acc_test.go ├── .gitignore ├── .golangci.yml ├── README.md ├── Makefile └── .goreleaser.yml /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: plumbing 2 | -------------------------------------------------------------------------------- /examples/k8s/base/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | awx = { 4 | source = "github.com/mrcrilly/awx" 5 | version = "0.1" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/k8s/data/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | awx = { 4 | source = "github.com/mrcrilly/awx" 5 | version = "0.1" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tools/mage.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "os" 7 | 8 | "github.com/magefile/mage/mage" 9 | ) 10 | 11 | func main() { os.Exit(mage.Main()) } 12 | -------------------------------------------------------------------------------- /examples/k8s/base/provider.tf: -------------------------------------------------------------------------------- 1 | provider "awx" { 2 | hostname = "http://awx.172.21.0.2.sslip.io" 3 | #hostname = "http://localhost:8078" 4 | username = "test" 5 | password = "changeme" 6 | } 7 | -------------------------------------------------------------------------------- /examples/k8s/data/provider.tf: -------------------------------------------------------------------------------- 1 | provider "awx" { 2 | hostname = "http://awx.172.21.0.2.sslip.io" 3 | #hostname = "http://localhost:8078" 4 | username = "test" 5 | password = "changeme" 6 | } 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "gomod" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | -------------------------------------------------------------------------------- /awx/convert_type.go: -------------------------------------------------------------------------------- 1 | package awx 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | // AtoipOr takes a string and a defaultValue. If the string cannot be converted, defaultValue is returned 8 | func AtoipOr(s string, defaultValue *int) *int { 9 | n, err := strconv.Atoi(s) 10 | if err != nil { 11 | return defaultValue 12 | } 13 | return &n 14 | } 15 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 6 | 7 | "github.com/mrcrilly/terraform-provider-awx/awx" 8 | ) 9 | 10 | func main() { 11 | plugin.Serve(&plugin.ServeOpts{ 12 | ProviderFunc: func() *schema.Provider { 13 | return awx.Provider() 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | # awx Provider 3 | 4 | Ansible Tower Provider for handle Tower Projects with [rest](https://docs.ansible.com/ansible-tower/latest/html/towerapi/api_ref.html) 5 | 6 | ## Example Usage 7 | 8 | ```hcl 9 | provider "awx" { 10 | hostname = "http://localhost:8078" 11 | username = "test" 12 | password = "changeme" 13 | } 14 | ``` 15 | 16 | ## Argument Reference 17 | 18 | * List any arguments for the provider **block.** 19 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mrcrilly/terraform-provider-awx 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/gruntwork-io/terratest v0.31.2 7 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0 8 | github.com/mrcrilly/goawx v0.1.4 9 | github.com/stretchr/testify v1.6.1 10 | gopkg.in/yaml.v2 v2.3.0 11 | ) 12 | 13 | replace github.com/mrcrilly/goawx => github.com/nolte/goawx v0.1.6 14 | 15 | // replace github.com/mrcrilly/goawx => /go/src/github.com/mrcrilly/goawx 16 | -------------------------------------------------------------------------------- /docs/data-sources/project.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_project" 4 | sidebar_current: "docs-awx-datasource-project" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_project 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_project" "default" { 17 | name = "Default" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | The following arguments are supported: 24 | 25 | * `id` - (Optional) 26 | * `name` - (Optional) 27 | 28 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${fileDirname}", 13 | "env": {}, 14 | "args": [] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [docs/**.md] 13 | # allow line break https://3os.org/markdownCheatSheet/lineBreaks/#line_break_with_2_spaces 14 | trim_trailing_whitespace = false 15 | 16 | [{makefile,Makefile}] 17 | indent_style = tabs 18 | 19 | [{*.yml,*.yaml, *.tf}] 20 | indent_style = space 21 | indent_size = 2 22 | -------------------------------------------------------------------------------- /docs/data-sources/job_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_job_template" 4 | sidebar_current: "docs-awx-datasource-job_template" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_job_template 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_job_template" "default" { 17 | name = "Default" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | The following arguments are supported: 24 | 25 | * `id` - (Optional) 26 | * `name` - (Optional) 27 | 28 | -------------------------------------------------------------------------------- /docs/data-sources/organization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_organization" 4 | sidebar_current: "docs-awx-datasource-organization" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_organization 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_organization" "default" { 17 | name = "Default" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | The following arguments are supported: 24 | 25 | * `id` - (Optional) 26 | * `name` - (Optional) 27 | 28 | -------------------------------------------------------------------------------- /docs/resources/inventory_group.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_inventory_group" 4 | sidebar_current: "docs-awx-resource-inventory_group" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_inventory_group 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `name` - (Required) 24 | * `description` - (Optional) 25 | * `inventory_id` - (Optional, ForceNew) 26 | * `variables` - (Optional) 27 | 28 | -------------------------------------------------------------------------------- /docs/data-sources/workflow_job_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template" 4 | sidebar_current: "docs-awx-datasource-workflow_job_template" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_workflow_job_template" "default" { 17 | name = "Default" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | The following arguments are supported: 24 | 25 | * `id` - (Optional) 26 | * `name` - (Optional) 27 | 28 | -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mrcrilly/terraform-provider-awx/tools 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/hashicorp/terraform v0.13.2 7 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0 8 | github.com/hashicorp/terraform-plugin-test/v2 v2.1.2 // indirect 9 | github.com/magefile/mage v1.10.0 10 | github.com/mrcrilly/terraform-provider-awx v0.1.2 11 | github.com/nolte/plumbing v0.0.1 12 | ) 13 | 14 | replace github.com/mrcrilly/goawx => github.com/nolte/goawx v0.1.6 15 | 16 | replace github.com/mrcrilly/terraform-provider-awx => ../. 17 | -------------------------------------------------------------------------------- /docs/resources/credential_input_source.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential_input_source" 4 | sidebar_current: "docs-awx-resource-credential_input_source" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_credential_input_source 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `input_field_name` - (Required) 24 | * `source` - (Required) 25 | * `target` - (Required) 26 | * `description` - (Optional) 27 | * `metadata` - (Optional) 28 | 29 | -------------------------------------------------------------------------------- /docs/data-sources/inventory.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_inventory" 4 | sidebar_current: "docs-awx-datasource-inventory" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_inventory 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_inventory" "default" { 17 | name = "private_services" 18 | organisation_id = data.awx_organization.default.id 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | The following arguments are supported: 25 | 26 | * `id` - (Optional) 27 | * `name` - (Optional) 28 | * `organisation_id` - (Optional) 29 | 30 | -------------------------------------------------------------------------------- /examples/k8s/data/main.tf: -------------------------------------------------------------------------------- 1 | data "awx_organization" "default" { 2 | name = "acc-test" 3 | } 4 | 5 | 6 | data "awx_job_template" "template" { 7 | name = "acc-job-template" 8 | } 9 | 10 | output "job" { 11 | value = data.awx_job_template.template 12 | } 13 | 14 | data "awx_project" "this" { 15 | name = "acc-project" 16 | } 17 | 18 | output "project" { 19 | value = data.awx_project.this 20 | } 21 | 22 | #data "awx_workflow_job_template" "template" { 23 | # name = "acc-workflow-job" 24 | #} 25 | # 26 | #output "workflow" { 27 | # value = data.awx_workflow_job_template.template 28 | #} 29 | -------------------------------------------------------------------------------- /docs/data-sources/inventory_group.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_inventory_group" 4 | sidebar_current: "docs-awx-datasource-inventory_group" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_inventory_group 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_inventory_group" "default" { 17 | name = "k3sPrimary" 18 | inventory_id = data.awx_inventory.default.id 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | The following arguments are supported: 25 | 26 | * `inventory_id` - (Required) 27 | * `id` - (Optional) 28 | * `name` - (Optional) 29 | 30 | -------------------------------------------------------------------------------- /docs/resources/credential_scm.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential_scm" 4 | sidebar_current: "docs-awx-resource-credential_scm" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_credential_scm 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `name` - (Required) 24 | * `organisation_id` - (Required) 25 | * `description` - (Optional) 26 | * `password` - (Optional) 27 | * `ssh_key_data` - (Optional) 28 | * `ssh_key_unlock` - (Optional) 29 | * `username` - (Optional) 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - develop 8 | 9 | jobs: 10 | update_release_draft: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # Drafts your next Release notes as Pull Requests are merged into "master" 14 | - uses: release-drafter/release-drafter@v5 15 | # with: 16 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 17 | # config-name: my-config.yml 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /docs/resources/credential_azure_key_vault.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential_azure_key_vault" 4 | sidebar_current: "docs-awx-resource-credential_azure_key_vault" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_credential_azure_key_vault 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `client` - (Required) 24 | * `name` - (Required) 25 | * `organisation_id` - (Required) 26 | * `secret` - (Required) 27 | * `tenant` - (Required) 28 | * `url` - (Required) 29 | * `description` - (Optional) 30 | 31 | -------------------------------------------------------------------------------- /docs/data-sources/credentials.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credentials" 4 | sidebar_current: "docs-awx-datasource-credentials" 5 | description: |- 6 | Use this data source to query Credential by ID. 7 | --- 8 | 9 | # awx_credentials 10 | 11 | Use this data source to query Credential by ID. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | 24 | 25 | ## Attributes Reference 26 | 27 | In addition to all arguments above, the following attributes are exported: 28 | 29 | * `credentials` - 30 | * `id` - 31 | * `kind` - 32 | * `username` - 33 | -------------------------------------------------------------------------------- /docs/resources/job_template_credential.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_job_template_credential" 4 | sidebar_current: "docs-awx-resource-job_template_credential" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_job_template_credential 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "awx_job_template_credentials" "baseconfig" { 17 | job_template_id = awx_job_template.baseconfig.id 18 | credential_id = awx_credential_machine.pi_connection.id 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | The following arguments are supported: 25 | 26 | * `credential_id` - (Required, ForceNew) 27 | * `job_template_id` - (Required, ForceNew) 28 | 29 | -------------------------------------------------------------------------------- /docs/resources/inventory_source.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_inventory_source" 4 | sidebar_current: "docs-awx-resource-inventory_source" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_inventory_source 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `inventory_id` - (Required, ForceNew) 24 | * `name` - (Required) 25 | * `source_project_id` - (Required) 26 | * `overwrite_vars` - (Optional) 27 | * `source_path` - (Optional, ForceNew) 28 | * `source` - (Optional) 29 | * `update_cache_timeout` - (Optional) 30 | * `verbosity` - (Optional) 31 | 32 | -------------------------------------------------------------------------------- /docs/data-sources/credential.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential" 4 | sidebar_current: "docs-awx-datasource-credential" 5 | description: |- 6 | Use this data source to query Credential by ID. 7 | --- 8 | 9 | # awx_credential 10 | 11 | Use this data source to query Credential by ID. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `id` - (Required) Credential id 24 | 25 | ## Attributes Reference 26 | 27 | In addition to all arguments above, the following attributes are exported: 28 | 29 | * `kind` - The Kind from searched id 30 | * `username` - The Username from searched id 31 | -------------------------------------------------------------------------------- /docs/resources/organization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_organization" 4 | sidebar_current: "docs-awx-resource-organization" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_organization 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "awx_organization" "default" { 17 | name = "acc-test" 18 | } 19 | ``` 20 | 21 | ## Argument Reference 22 | 23 | The following arguments are supported: 24 | 25 | * `name` - (Required) 26 | * `custom_virtualenv` - (Optional) Local absolute file path containing a custom Python virtualenv to use 27 | * `description` - (Optional) 28 | * `max_hosts` - (Optional) Maximum number of hosts allowed to be managed by this organization 29 | 30 | -------------------------------------------------------------------------------- /docs/data-sources/credential_azure_key_vault.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential_azure_key_vault" 4 | sidebar_current: "docs-awx-datasource-credential_azure_key_vault" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_credential_azure_key_vault 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `credential_id` - (Required) 24 | 25 | ## Attributes Reference 26 | 27 | In addition to all arguments above, the following attributes are exported: 28 | 29 | * `client` - 30 | * `description` - 31 | * `name` - 32 | * `organisation_id` - 33 | * `secret` - 34 | * `tenant` - 35 | * `url` - 36 | -------------------------------------------------------------------------------- /examples/k8s/base/files/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDFfyuCPV/U92QRS9zRXPJhY1DUZQHf3fc/qnkUxY1RQ7492tcJoOhFoTIyonq6uS8WJFSFADPcY2lhXdtRsLZrIqgVMNNvN5Hv8QMI4/WZsPb7juGdrBPogQcX3xpEJtD5tJOptHlnY1StCLw54RcsysCPPBI/yQNF5yM7jXgF+75O0a2NRhvTH0V1CxhgPuiz9Io1HZqrw7Rv9uYhpTh1XaZYhfpWAeAEbHvHG+HBlm27NYY2Oolr5vdu8mfK7w+A0NMLCu5cuK6OKIOMHG09IXKuO7SfZelEDPYios1Ubm/oDqfb1eiM71ZoErMzz2RxRZ8E7wT++V3Yv5/yPS8v0nSIKFco/2NpC4IFSbPZG2AF6roRNGtTtTXErxTZbgOL2VPOhCLiJx1H+a4wq5ksnb3zUq7+mgSPtI6zmcZ2Up9UbqvAFfDuF1EJ5MoYMakLYq7SGImPraUxnOifUtMvhI02j1NDlsDxM+Z2nvZvQepxYt6G86ShbJEHxhlJ8SpgCO3JTfW94zkMLE4UNalPoB2WgIQr6RUdlDGbfbRjHWS2o8X/AsejVJQe78gge6GUKCrKW0y1mKUqpu1XgSJhEAl/fnDeQ347OU5/5qePUBmqP1fKGJvgWcMWnVEiBfTiAGJY7FkIvPCjIohUzzbkL4CG77NF/hSIMhQWS90GVw== your_email@example.com 2 | -------------------------------------------------------------------------------- /docs/resources/credential_machine.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_credential_machine" 4 | sidebar_current: "docs-awx-resource-credential_machine" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_credential_machine 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | *TBD* 17 | ``` 18 | 19 | ## Argument Reference 20 | 21 | The following arguments are supported: 22 | 23 | * `name` - (Required) 24 | * `organisation_id` - (Required) 25 | * `become_method` - (Optional) 26 | * `become_password` - (Optional) 27 | * `become_username` - (Optional) 28 | * `description` - (Optional) 29 | * `password` - (Optional) 30 | * `ssh_key_data` - (Optional) 31 | * `ssh_key_unlock` - (Optional) 32 | * `ssh_public_key_data` - (Optional) 33 | * `username` - (Optional) 34 | 35 | -------------------------------------------------------------------------------- /docs/resources/inventory.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_inventory" 4 | sidebar_current: "docs-awx-resource-inventory" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_inventory 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_organization" "default" { 17 | name = "Default" 18 | } 19 | 20 | resource "awx_inventory" "default" { 21 | name = "acc-test" 22 | organisation_id = data.awx_organization.default.id 23 | variables = < Install Operator..." 3 | kubectl apply -f https://raw.githubusercontent.com/ansible/awx-operator/devel/deploy/awx-operator.yaml 4 | 5 | echo "==> Wait Operator started..." 6 | kubectl wait --for=condition=ready pod -l name=awx-operator 7 | 8 | echo "==> Starting AWX Test installation..." 9 | kubectl create ns ansible-awx 10 | # kubectl delete AWX awx -n ansible-awx 11 | KUBENODE_IP=$(kubectl get node -ojson | jq '.items[0].status.addresses[0].address' -r) 12 | INGRESS_DOMAIN="${KUBENODE_IP}.sslip.io" 13 | 14 | cat < Waiting Operator Started the AWX Deployment..." 31 | sleep 45 32 | 33 | echo "==> Waiting AWX full Started..." 34 | kubectl wait --for=condition=ready pod -l app=awx -n ansible-awx --timeout=800s 35 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - bodyclose 5 | - deadcode 6 | - depguard 7 | - dogsled 8 | - errcheck 9 | - funlen 10 | - gochecknoinits 11 | - goconst 12 | - gocritic 13 | - gocyclo 14 | - gofmt 15 | - goimports 16 | - golint 17 | - gomnd 18 | - goprintffuncname 19 | - gosec 20 | - gosimple 21 | - govet 22 | - ineffassign 23 | - interfacer 24 | - lll 25 | - misspell 26 | - nakedret 27 | - nolintlint 28 | - rowserrcheck 29 | - scopelint 30 | - staticcheck 31 | - structcheck 32 | - stylecheck 33 | - typecheck 34 | - unconvert 35 | - unparam 36 | - unused 37 | - varcheck 38 | - whitespace 39 | - asciicheck 40 | - gochecknoglobals 41 | - gocognit 42 | - godot 43 | - godox 44 | - maligned 45 | - prealloc 46 | - testpackage 47 | - wsl 48 | # don't enable: 49 | #- nestif 50 | #- dupl 51 | #- goerr113 52 | issues: 53 | # Excluding configuration per-path, per-linter, per-text and per-source 54 | exclude-rules: 55 | # Exclude some linters from running on tests files. 56 | - path: _test\.go 57 | linters: 58 | - gochecknoglobals 59 | - gochecknoinits 60 | -------------------------------------------------------------------------------- /docs/resources/workflow_job_template_node.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template_node" 4 | sidebar_current: "docs-awx-resource-workflow_job_template_node" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template_node 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "random_uuid" "workflow_node_base_uuid" {} 17 | 18 | resource "awx_workflow_job_template_node" "default" { 19 | workflow_job_template_id = awx_workflow_job_template.default.id 20 | unified_job_template_id = awx_job_template.baseconfig.id 21 | inventory_id = awx_inventory.default.id 22 | identifier = random_uuid.workflow_node_base_uuid.result 23 | } 24 | ``` 25 | 26 | ## Argument Reference 27 | 28 | The following arguments are supported: 29 | 30 | * `identifier` - (Required) 31 | * `unified_job_template_id` - (Required) 32 | * `workflow_job_template_id` - (Required) 33 | * `all_parents_must_converge` - (Optional) 34 | * `diff_mode` - (Optional) 35 | * `extra_data` - (Optional) 36 | * `inventory_id` - (Optional) Inventory applied as a prompt, assuming job template prompts for inventory. 37 | * `job_tags` - (Optional) 38 | * `job_type` - (Optional) 39 | * `limit` - (Optional) 40 | * `scm_branch` - (Optional) 41 | * `skip_tags` - (Optional) 42 | * `verbosity` - (Optional) 43 | 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Provider AWX 2 | 3 | _Fork from [mrcrilly/terraform-provider-awx](https://github.com/mrcrilly/terraform-provider-awx) for develop additional functions_ 4 | 5 | Coming soon. 6 | 7 | ## Local Development 8 | 9 | ```sh 10 | # Start a Local AWX deployed to a Kind 11 | cd ./tools && go run mage.go -v reCreate && cd .. 12 | ``` 13 | 14 | ```sh 15 | # Build Provider 16 | goreleaser build --snapshot --rm-dist 17 | 18 | # Copy Provider 19 | mkdir -p ~/.terraform.d/plugins/github.com/mrcrilly/awx/0.1/linux_amd64/terraform-provider-awx 20 | find ./dist/terraform-provider-awx_linux_amd64/* -name 'terraform-provider-awx*' -print0 | xargs -0 -I {} mv {} ~/.terraform.d/plugins/github.com/mrcrilly/awx/0.1/linux_amd64/terraform-provider-awx 21 | 22 | # start the Tests 23 | go test ./test -count=1 24 | 25 | # or as one command 26 | goreleaser build --snapshot --rm-dist \ 27 | && mkdir -p ~/.terraform.d/plugins/github.com/mrcrilly/awx/0.1/linux_amd64/ \ 28 | && find ./dist/terraform-provider-awx_linux_amd64/* -name 'terraform-provider-awx*' -print0 | xargs -0 -I {} mv {} ~/.terraform.d/plugins/github.com/mrcrilly/awx/0.1/linux_amd64/terraform-provider-awx \ 29 | && go test ./test -count=1 30 | 31 | 32 | ``` 33 | 34 | ## Documentation 35 | 36 | The files from `./docs` are generated by `cd ./tools && go run mage.go -v genDocumentuation && cd ..` 37 | -------------------------------------------------------------------------------- /docs/resources/workflow_job_template_node_allways.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template_node_allways" 4 | sidebar_current: "docs-awx-resource-workflow_job_template_node_allways" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template_node_allways 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "random_uuid" "workflow_node_k3s_uuid" {} 17 | 18 | resource "awx_workflow_job_template_node_allways" "k3s" { 19 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 20 | unified_job_template_id = awx_job_template.k3s.id 21 | inventory_id = awx_inventory.default.id 22 | identifier = random_uuid.workflow_node_k3s_uuid.result 23 | } 24 | ``` 25 | 26 | ## Argument Reference 27 | 28 | The following arguments are supported: 29 | 30 | * `identifier` - (Required) 31 | * `unified_job_template_id` - (Required) 32 | * `all_parents_must_converge` - (Optional) 33 | * `diff_mode` - (Optional) 34 | * `extra_data` - (Optional) 35 | * `inventory_id` - (Optional) Inventory applied as a prompt, assuming job template prompts for inventory. 36 | * `job_tags` - (Optional) 37 | * `job_type` - (Optional) 38 | * `limit` - (Optional) 39 | * `scm_branch` - (Optional) 40 | * `skip_tags` - (Optional) 41 | * `verbosity` - (Optional) 42 | * `workflow_job_template_node_id` - (Optional) 43 | 44 | -------------------------------------------------------------------------------- /docs/resources/workflow_job_template_node_failure.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template_node_failure" 4 | sidebar_current: "docs-awx-resource-workflow_job_template_node_failure" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template_node_failure 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "random_uuid" "workflow_node_k3s_uuid" {} 17 | 18 | resource "awx_workflow_job_template_node_failure" "k3s" { 19 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 20 | unified_job_template_id = awx_job_template.k3s.id 21 | inventory_id = awx_inventory.default.id 22 | identifier = random_uuid.workflow_node_k3s_uuid.result 23 | } 24 | ``` 25 | 26 | ## Argument Reference 27 | 28 | The following arguments are supported: 29 | 30 | * `identifier` - (Required) 31 | * `unified_job_template_id` - (Required) 32 | * `all_parents_must_converge` - (Optional) 33 | * `diff_mode` - (Optional) 34 | * `extra_data` - (Optional) 35 | * `inventory_id` - (Optional) Inventory applied as a prompt, assuming job template prompts for inventory. 36 | * `job_tags` - (Optional) 37 | * `job_type` - (Optional) 38 | * `limit` - (Optional) 39 | * `scm_branch` - (Optional) 40 | * `skip_tags` - (Optional) 41 | * `verbosity` - (Optional) 42 | * `workflow_job_template_node_id` - (Optional) 43 | 44 | -------------------------------------------------------------------------------- /docs/resources/workflow_job_template_node_success.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template_node_success" 4 | sidebar_current: "docs-awx-resource-workflow_job_template_node_success" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template_node_success 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "random_uuid" "workflow_node_k3s_uuid" {} 17 | 18 | resource "awx_workflow_job_template_node_success" "k3s" { 19 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 20 | unified_job_template_id = awx_job_template.k3s.id 21 | inventory_id = awx_inventory.default.id 22 | identifier = random_uuid.workflow_node_k3s_uuid.result 23 | } 24 | ``` 25 | 26 | ## Argument Reference 27 | 28 | The following arguments are supported: 29 | 30 | * `identifier` - (Required) 31 | * `unified_job_template_id` - (Required) 32 | * `all_parents_must_converge` - (Optional) 33 | * `diff_mode` - (Optional) 34 | * `extra_data` - (Optional) 35 | * `inventory_id` - (Optional) Inventory applied as a prompt, assuming job template prompts for inventory. 36 | * `job_tags` - (Optional) 37 | * `job_type` - (Optional) 38 | * `limit` - (Optional) 39 | * `scm_branch` - (Optional) 40 | * `skip_tags` - (Optional) 41 | * `verbosity` - (Optional) 42 | * `workflow_job_template_node_id` - (Optional) 43 | 44 | -------------------------------------------------------------------------------- /docs/resources/workflow_job_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_workflow_job_template" 4 | sidebar_current: "docs-awx-resource-workflow_job_template" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_workflow_job_template 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "awx_workflow_job_template" "default" { 17 | name = "workflow-job" 18 | organisation_id = var.organisation_id 19 | inventory_id = awx_inventory.default.id 20 | } 21 | ``` 22 | 23 | ## Argument Reference 24 | 25 | The following arguments are supported: 26 | 27 | * `name` - (Required) Name of this workflow job template. (string, required) 28 | * `allow_simultaneous` - (Optional) 29 | * `ask_inventory_on_launch` - (Optional) 30 | * `ask_limit_on_launch` - (Optional) 31 | * `ask_scm_branch_on_launch` - (Optional) 32 | * `ask_variables_on_launch` - (Optional) 33 | * `description` - (Optional) Optional description of this workflow job template. 34 | * `inventory_id` - (Optional) Inventory applied as a prompt, assuming job template prompts for inventory. 35 | * `limit` - (Optional) 36 | * `organisation_id` - (Optional) The organization used to determine access to this template. (id, default=``) 37 | * `scm_branch` - (Optional) 38 | * `survey_enabled` - (Optional) 39 | * `variables` - (Optional) 40 | * `webhook_credential` - (Optional) 41 | * `webhook_service` - (Optional) 42 | 43 | -------------------------------------------------------------------------------- /awx/resource_workflow_job_template_node_allways.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "random_uuid" "workflow_node_k3s_uuid" {} 8 | 9 | resource "awx_workflow_job_template_node_allways" "k3s" { 10 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 11 | unified_job_template_id = awx_job_template.k3s.id 12 | inventory_id = awx_inventory.default.id 13 | identifier = random_uuid.workflow_node_k3s_uuid.result 14 | } 15 | ``` 16 | 17 | */ 18 | package awx 19 | 20 | import ( 21 | "context" 22 | 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 24 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 25 | awx "github.com/mrcrilly/goawx/client" 26 | ) 27 | 28 | func resourceWorkflowJobTemplateNodeAllways() *schema.Resource { 29 | return &schema.Resource{ 30 | CreateContext: resourceWorkflowJobTemplateNodeAllwaysCreate, 31 | ReadContext: resourceWorkflowJobTemplateNodeRead, 32 | UpdateContext: resourceWorkflowJobTemplateNodeUpdate, 33 | DeleteContext: resourceWorkflowJobTemplateNodeDelete, 34 | Schema: workflowJobNodeSchema, 35 | } 36 | } 37 | func resourceWorkflowJobTemplateNodeAllwaysCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 38 | client := m.(*awx.AWX) 39 | awxService := client.WorkflowJobTemplateNodeAllwaysService 40 | return createNodeForWorkflowJob(awxService, ctx, d, m) 41 | } 42 | -------------------------------------------------------------------------------- /awx/resource_workflow_job_template_node_failure.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "random_uuid" "workflow_node_k3s_uuid" {} 8 | 9 | resource "awx_workflow_job_template_node_failure" "k3s" { 10 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 11 | unified_job_template_id = awx_job_template.k3s.id 12 | inventory_id = awx_inventory.default.id 13 | identifier = random_uuid.workflow_node_k3s_uuid.result 14 | } 15 | ``` 16 | 17 | */ 18 | package awx 19 | 20 | import ( 21 | "context" 22 | 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 24 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 25 | awx "github.com/mrcrilly/goawx/client" 26 | ) 27 | 28 | func resourceWorkflowJobTemplateNodeFailure() *schema.Resource { 29 | return &schema.Resource{ 30 | CreateContext: resourceWorkflowJobTemplateNodeFailureCreate, 31 | ReadContext: resourceWorkflowJobTemplateNodeRead, 32 | UpdateContext: resourceWorkflowJobTemplateNodeUpdate, 33 | DeleteContext: resourceWorkflowJobTemplateNodeDelete, 34 | Schema: workflowJobNodeSchema, 35 | } 36 | } 37 | 38 | func resourceWorkflowJobTemplateNodeFailureCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 39 | client := m.(*awx.AWX) 40 | awxService := client.WorkflowJobTemplateNodeFailureService 41 | return createNodeForWorkflowJob(awxService, ctx, d, m) 42 | } 43 | -------------------------------------------------------------------------------- /awx/resource_workflow_job_template_node_success.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "random_uuid" "workflow_node_k3s_uuid" {} 8 | 9 | resource "awx_workflow_job_template_node_success" "k3s" { 10 | workflow_job_template_node_id = awx_workflow_job_template_node.default.id 11 | unified_job_template_id = awx_job_template.k3s.id 12 | inventory_id = awx_inventory.default.id 13 | identifier = random_uuid.workflow_node_k3s_uuid.result 14 | } 15 | ``` 16 | 17 | */ 18 | package awx 19 | 20 | import ( 21 | "context" 22 | 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 24 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 25 | awx "github.com/mrcrilly/goawx/client" 26 | ) 27 | 28 | func resourceWorkflowJobTemplateNodeSuccess() *schema.Resource { 29 | return &schema.Resource{ 30 | CreateContext: resourceWorkflowJobTemplateNodeSuccessCreate, 31 | ReadContext: resourceWorkflowJobTemplateNodeRead, 32 | UpdateContext: resourceWorkflowJobTemplateNodeUpdate, 33 | DeleteContext: resourceWorkflowJobTemplateNodeDelete, 34 | Schema: workflowJobNodeSchema, 35 | } 36 | } 37 | 38 | func resourceWorkflowJobTemplateNodeSuccessCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 39 | 40 | client := m.(*awx.AWX) 41 | awxService := client.WorkflowJobTemplateNodeSuccessService 42 | return createNodeForWorkflowJob(awxService, ctx, d, m) 43 | } 44 | -------------------------------------------------------------------------------- /docs/resources/project.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_project" 4 | sidebar_current: "docs-awx-resource-project" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_project 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_organization" "default" { 17 | name = "Default" 18 | } 19 | 20 | resource "awx_project" "base_service_config" { 21 | name = "base-service-configuration" 22 | scm_type = "git" 23 | scm_url = "https://github.com/nolte/ansible_playbook-baseline-online-server" 24 | scm_branch = "feature/centos8-v2" 25 | scm_update_on_launch = true 26 | organisation_id = data.awx_organization.default.id 27 | } 28 | ``` 29 | 30 | ## Argument Reference 31 | 32 | The following arguments are supported: 33 | 34 | * `name` - (Required) Name of this project 35 | * `organisation_id` - (Required) Numeric ID of the project organization 36 | * `scm_type` - (Required) One of "" (manual), git, hg, svn 37 | * `description` - (Optional) Optional description of this project. 38 | * `local_path` - (Optional) Local path (relative to PROJECTS_ROOT) containing playbooks and related files for this project. 39 | * `scm_branch` - (Optional) Specific branch, tag or commit to checkout. 40 | * `scm_clean` - (Optional) 41 | * `scm_credential_id` - (Optional) Numeric ID of the scm used credential 42 | * `scm_delete_on_update` - (Optional) 43 | * `scm_update_cache_timeout` - (Optional) 44 | * `scm_update_on_launch` - (Optional) 45 | * `scm_url` - (Optional) 46 | 47 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./... | grep -v 'vendor') 2 | HOSTNAME=github.com 3 | NAMESPACE=mrcrilly 4 | NAME=awx 5 | BINARY=terraform-provider-${NAME} 6 | VERSION=0.1 7 | OS_ARCH=linux_amd64 #darwin_amd64 8 | 9 | default: install 10 | 11 | build: 12 | go build -o ${BINARY} 13 | 14 | release: 15 | GOOS=darwin GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_darwin_amd64 16 | GOOS=freebsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_freebsd_386 17 | GOOS=freebsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_freebsd_amd64 18 | GOOS=freebsd GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_freebsd_arm 19 | GOOS=linux GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_linux_386 20 | GOOS=linux GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_linux_amd64 21 | GOOS=linux GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_linux_arm 22 | GOOS=openbsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_openbsd_386 23 | GOOS=openbsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_openbsd_amd64 24 | GOOS=solaris GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_solaris_amd64 25 | GOOS=windows GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_windows_386 26 | GOOS=windows GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_windows_amd64 27 | 28 | install: build 29 | mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 30 | mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 31 | 32 | test: 33 | go test -i $(TEST) || exit 1 34 | echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 35 | 36 | testacc: 37 | TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m 38 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | before: 4 | hooks: 5 | # this is just an example and not a requirement for provider building/publishing 6 | - go mod tidy 7 | builds: 8 | - env: 9 | # goreleaser does not work with CGO, it could also complicate 10 | # usage by users in CI/CD systems like Terraform Cloud where 11 | # they are unable to install libraries. 12 | - CGO_ENABLED=0 13 | mod_timestamp: '{{ .CommitTimestamp }}' 14 | flags: 15 | - -trimpath 16 | ldflags: 17 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 18 | goos: 19 | - freebsd 20 | - windows 21 | - linux 22 | - darwin 23 | goarch: 24 | - amd64 25 | - '386' 26 | - arm 27 | - arm64 28 | ignore: 29 | - goos: darwin 30 | goarch: '386' 31 | binary: '{{ .ProjectName }}_v{{ .Version }}' 32 | archives: 33 | - format: zip 34 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 35 | checksum: 36 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 37 | algorithm: sha256 38 | signs: 39 | - artifacts: checksum 40 | args: 41 | # if you are using this is a GitHub action or some other automated pipeline, you 42 | # need to pass the batch flag to indicate its not interactive. 43 | - "--batch" 44 | - "--local-user" 45 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 46 | - "--output" 47 | - "${signature}" 48 | - "--detach-sign" 49 | - "${artifact}" 50 | release: 51 | # Visit your project's GitHub Releases page to publish this release. 52 | draft: false 53 | changelog: 54 | skip: true 55 | 56 | -------------------------------------------------------------------------------- /awx/data_source_credential.go: -------------------------------------------------------------------------------- 1 | /* 2 | Use this data source to query Credential by ID. 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | *TBD* 8 | ``` 9 | 10 | */ 11 | package awx 12 | 13 | import ( 14 | "context" 15 | "strconv" 16 | "time" 17 | 18 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 20 | awx "github.com/mrcrilly/goawx/client" 21 | ) 22 | 23 | func dataSourceCredentialByID() *schema.Resource { 24 | return &schema.Resource{ 25 | ReadContext: dataSourceCredentialByIDRead, 26 | Schema: map[string]*schema.Schema{ 27 | "id": &schema.Schema{ 28 | Type: schema.TypeInt, 29 | Required: true, 30 | Description: "Credential id", 31 | }, 32 | "username": &schema.Schema{ 33 | Type: schema.TypeString, 34 | Computed: true, 35 | Description: "The Username from searched id", 36 | }, 37 | "kind": &schema.Schema{ 38 | Type: schema.TypeString, 39 | Computed: true, 40 | Description: "The Kind from searched id", 41 | }, 42 | }, 43 | } 44 | } 45 | 46 | func dataSourceCredentialByIDRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 47 | var diags diag.Diagnostics 48 | 49 | client := m.(*awx.AWX) 50 | id := d.Get("id").(int) 51 | cred, err := client.CredentialsService.GetCredentialsByID(id, map[string]string{}) 52 | if err != nil { 53 | diags = append(diags, diag.Diagnostic{ 54 | Severity: diag.Error, 55 | Summary: "Unable to fetch credential", 56 | Detail: "The given credential ID is invalid or malformed", 57 | }) 58 | } 59 | 60 | d.Set("username", cred.Inputs["username"]) 61 | d.Set("kind", cred.Kind) 62 | d.SetId(strconv.FormatInt(time.Now().Unix(), 10)) 63 | 64 | return diags 65 | } 66 | -------------------------------------------------------------------------------- /examples/awx/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | awx = { 4 | source = "github.com/mrcrilly/awx" 5 | version = "0.1" 6 | } 7 | } 8 | } 9 | 10 | provider "awx" {} 11 | provider "aws" { 12 | region = "ap-southeast-2" 13 | } 14 | 15 | provider "azurerm" { 16 | features {} 17 | } 18 | 19 | resource "aws_instance" "windows" { 20 | ami = "ami-0343f4bc3607550d2" 21 | instance_type = "t2.small" 22 | get_password_data = true 23 | key_name = "" 24 | 25 | tags = { 26 | Name = "deleteme" 27 | } 28 | } 29 | 30 | data "azurerm_key_vault" "example" { 31 | name = "" 32 | resource_group_name = "" 33 | } 34 | 35 | data "azurerm_key_vault_secret" "example" { 36 | name = "windows-server-pem-file" 37 | key_vault_id = data.azurerm_key_vault.example.id 38 | } 39 | 40 | locals { 41 | decrypted_password = rsadecrypt(aws_instance.windows.password_data, base64decode(data.azurerm_key_vault_secret.example.value)) 42 | } 43 | 44 | resource "azurerm_key_vault_secret" "example" { 45 | name = "deleteme-windows-server" 46 | value = local.decrypted_password 47 | key_vault_id = data.azurerm_key_vault.example.id 48 | } 49 | 50 | resource "awx_credential_machine" "windows" { 51 | organisation_id = 1 52 | name = "Windows Server 2018" 53 | username = "administrator" 54 | } 55 | 56 | resource "awx_credential_input_source" "azure-to-windows" { 57 | description = "link azure key vault secret to windows server" 58 | input_field_name = "password" 59 | target = awx_credential_machine.windows.id 60 | source = awx_credential_azure_key_vault.windows.id 61 | metadata = { 62 | secret_field = azurerm_key_vault_secret.example.name 63 | } 64 | } 65 | 66 | resource "awx_credential_azure_key_vault" "windows" { 67 | name = "Primary Key Vault" 68 | organisation_id = 1 69 | url = data.azurerm_key_vault.example.vault_uri 70 | client = "" 71 | secret = "" 72 | tenant = data.azurerm_key_vault.example.tenant_id 73 | } 74 | 75 | -------------------------------------------------------------------------------- /awx/data_source_project.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_project" "default" { 8 | name = "Default" 9 | } 10 | ``` 11 | 12 | */ 13 | package awx 14 | 15 | import ( 16 | "context" 17 | "strconv" 18 | 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 21 | awx "github.com/mrcrilly/goawx/client" 22 | ) 23 | 24 | func dataSourceProject() *schema.Resource { 25 | return &schema.Resource{ 26 | ReadContext: dataSourceProjectsRead, 27 | Schema: map[string]*schema.Schema{ 28 | "id": &schema.Schema{ 29 | Type: schema.TypeInt, 30 | Optional: true, 31 | Computed: true, 32 | }, 33 | "name": &schema.Schema{ 34 | Type: schema.TypeString, 35 | Optional: true, 36 | Computed: true, 37 | }, 38 | }, 39 | } 40 | } 41 | 42 | func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 43 | var diags diag.Diagnostics 44 | client := m.(*awx.AWX) 45 | params := make(map[string]string) 46 | if groupName, okName := d.GetOk("name"); okName { 47 | params["name"] = groupName.(string) 48 | } 49 | 50 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 51 | params["id"] = strconv.Itoa(groupID.(int)) 52 | } 53 | 54 | if len(params) == 0 { 55 | return buildDiagnosticsMessage( 56 | "Get: Missing Parameters", 57 | "Please use one of the selectors (name or group_id)", 58 | ) 59 | } 60 | Projects, _, err := client.ProjectService.ListProjects(params) 61 | if err != nil { 62 | return buildDiagnosticsMessage( 63 | "Get: Fail to fetch Inventory Group", 64 | "Fail to find the group got: %s", 65 | err.Error(), 66 | ) 67 | } 68 | if len(Projects) > 1 { 69 | return buildDiagnosticsMessage( 70 | "Get: find more than one Element", 71 | "The Query Returns more than one Group, %d", 72 | len(Projects), 73 | ) 74 | } 75 | 76 | Project := Projects[0] 77 | d = setProjectResourceData(d, Project) 78 | return diags 79 | } 80 | -------------------------------------------------------------------------------- /docs/resources/job_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "awx" 3 | page_title: "AWX: awx_job_template" 4 | sidebar_current: "docs-awx-resource-job_template" 5 | description: |- 6 | *TBD* 7 | --- 8 | 9 | # awx_job_template 10 | 11 | *TBD* 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "awx_inventory" "default" { 17 | name = "private_services" 18 | organisation_id = data.awx_organization.default.id 19 | } 20 | 21 | resource "awx_job_template" "baseconfig" { 22 | name = "baseconfig" 23 | job_type = "run" 24 | inventory_id = data.awx_inventory.default.id 25 | project_id = awx_project.base_service_config.id 26 | playbook = "master-configure-system.yml" 27 | become_enabled = true 28 | } 29 | ``` 30 | 31 | ## Argument Reference 32 | 33 | The following arguments are supported: 34 | 35 | * `inventory_id` - (Required) 36 | * `job_type` - (Required) One of: run, check, scan 37 | * `name` - (Required) 38 | * `project_id` - (Required) 39 | * `allow_simultaneous` - (Optional) 40 | * `ask_credential_on_launch` - (Optional) 41 | * `ask_diff_mode_on_launch` - (Optional) 42 | * `ask_inventory_on_launch` - (Optional) 43 | * `ask_job_type_on_launch` - (Optional) 44 | * `ask_limit_on_launch` - (Optional) 45 | * `ask_skip_tags_on_launch` - (Optional) 46 | * `ask_tags_on_launch` - (Optional) 47 | * `ask_variables_on_launch` - (Optional) 48 | * `ask_verbosity_on_launch` - (Optional) 49 | * `become_enabled` - (Optional) 50 | * `custom_virtualenv` - (Optional) 51 | * `description` - (Optional) 52 | * `diff_mode` - (Optional) 53 | * `extra_vars` - (Optional) 54 | * `force_handlers` - (Optional) 55 | * `forks` - (Optional) 56 | * `host_config_key` - (Optional) 57 | * `job_tags` - (Optional) 58 | * `limit` - (Optional) 59 | * `playbook` - (Optional) 60 | * `skip_tags` - (Optional) 61 | * `start_at_task` - (Optional) 62 | * `survey_enabled` - (Optional) 63 | * `timeout` - (Optional) 64 | * `use_fact_cache` - (Optional) 65 | * `verbosity` - (Optional) One of 0,1,2,3,4,5 66 | 67 | -------------------------------------------------------------------------------- /awx/data_source_organization.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_organization" "default" { 8 | name = "Default" 9 | } 10 | ``` 11 | 12 | */ 13 | package awx 14 | 15 | import ( 16 | "context" 17 | "strconv" 18 | 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 21 | awx "github.com/mrcrilly/goawx/client" 22 | ) 23 | 24 | func dataSourceOrganization() *schema.Resource { 25 | return &schema.Resource{ 26 | ReadContext: dataSourceOrganizationsRead, 27 | Schema: map[string]*schema.Schema{ 28 | "id": &schema.Schema{ 29 | Type: schema.TypeInt, 30 | Optional: true, 31 | Computed: true, 32 | }, 33 | "name": &schema.Schema{ 34 | Type: schema.TypeString, 35 | Optional: true, 36 | Computed: true, 37 | }, 38 | }, 39 | } 40 | } 41 | 42 | func dataSourceOrganizationsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 43 | var diags diag.Diagnostics 44 | client := m.(*awx.AWX) 45 | params := make(map[string]string) 46 | if groupName, okName := d.GetOk("name"); okName { 47 | params["name"] = groupName.(string) 48 | } 49 | 50 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 51 | params["id"] = strconv.Itoa(groupID.(int)) 52 | } 53 | 54 | if len(params) == 0 { 55 | return buildDiagnosticsMessage( 56 | "Get: Missing Parameters", 57 | "Please use one of the selectors (name or group_id)", 58 | ) 59 | return diags 60 | } 61 | organizations, _, err := client.OrganizationsService.ListOrganizations(params) 62 | if err != nil { 63 | return buildDiagnosticsMessage( 64 | "Get: Fail to fetch Inventory Group", 65 | "Fail to find the group got: %s", 66 | err.Error(), 67 | ) 68 | } 69 | if len(organizations) > 1 { 70 | return buildDiagnosticsMessage( 71 | "Get: find more than one Element", 72 | "The Query Returns more than one Group, %d", 73 | len(organizations), 74 | ) 75 | return diags 76 | } 77 | 78 | organization := organizations[0] 79 | d = setOrganizationsResourceData(d, organization) 80 | return diags 81 | } 82 | -------------------------------------------------------------------------------- /awx/data_source_credentials.go: -------------------------------------------------------------------------------- 1 | /* 2 | Use this data source to query Credential by ID. 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | *TBD* 8 | ``` 9 | 10 | */ 11 | package awx 12 | 13 | import ( 14 | "context" 15 | "strconv" 16 | "time" 17 | 18 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 20 | awx "github.com/mrcrilly/goawx/client" 21 | ) 22 | 23 | func dataSourceCredentials() *schema.Resource { 24 | return &schema.Resource{ 25 | ReadContext: dataSourceCredentialsRead, 26 | Schema: map[string]*schema.Schema{ 27 | "credentials": &schema.Schema{ 28 | Type: schema.TypeList, 29 | Computed: true, 30 | Elem: &schema.Resource{ 31 | Schema: map[string]*schema.Schema{ 32 | "id": &schema.Schema{ 33 | Type: schema.TypeInt, 34 | Computed: true, 35 | }, 36 | "username": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Computed: true, 39 | }, 40 | "kind": &schema.Schema{ 41 | Type: schema.TypeString, 42 | Computed: true, 43 | }, 44 | }, 45 | }, 46 | }, 47 | }, 48 | } 49 | } 50 | 51 | func dataSourceCredentialsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 52 | var diags diag.Diagnostics 53 | client := m.(*awx.AWX) 54 | 55 | creds, _, err := client.CredentialsService.ListCredentials(map[string]string{}) 56 | if err != nil { 57 | diags = append(diags, diag.Diagnostic{ 58 | Severity: diag.Error, 59 | Summary: "Unable to fetch credentials", 60 | Detail: "Unable to fetch credentials from AWX API", 61 | }) 62 | return diags 63 | } 64 | 65 | parsedCreds := make([]map[string]interface{}, 0) 66 | for _, c := range creds { 67 | parsedCreds = append(parsedCreds, map[string]interface{}{ 68 | "id": c.ID, 69 | "username": c.Inputs["username"], 70 | "kind": c.Kind, 71 | }) 72 | } 73 | 74 | err = d.Set("credentials", parsedCreds) 75 | if err != nil { 76 | return diag.FromErr(err) 77 | } 78 | 79 | d.SetId(strconv.FormatInt(time.Now().Unix(), 10)) 80 | 81 | return diags 82 | } 83 | -------------------------------------------------------------------------------- /tools/template.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | const ( 4 | docTPL = `--- 5 | layout: "{{.cloud_mark}}" 6 | page_title: "{{.cloud_title}}: {{.name}}" 7 | sidebar_current: "docs-{{.cloud_mark}}-{{.dtype}}-{{.resource}}" 8 | description: |- 9 | {{.description_short}} 10 | --- 11 | 12 | # {{.name}} 13 | 14 | {{.description}} 15 | 16 | ## Example Usage 17 | 18 | {{.example}} 19 | 20 | ## Argument Reference 21 | 22 | The following arguments are supported: 23 | 24 | {{.arguments}} 25 | {{ if ne .attributes ""}} 26 | ## Attributes Reference 27 | 28 | In addition to all arguments above, the following attributes are exported: 29 | 30 | {{.attributes}} 31 | {{- end}} 32 | {{- if ne .import ""}} 33 | ## Import 34 | 35 | {{.import}} 36 | {{- end}} 37 | ` 38 | idxTPL = ` 39 | <% wrap_layout :inner do %> 40 | <% content_for :sidebar do %> 41 | 62 | <% end %> 63 | <%= yield %> 64 | <% end %> 65 | ` 66 | ) 67 | -------------------------------------------------------------------------------- /awx/data_source_inventory_group.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_inventory_group" "default" { 8 | name = "k3sPrimary" 9 | inventory_id = data.awx_inventory.default.id 10 | } 11 | ``` 12 | 13 | */ 14 | package awx 15 | 16 | import ( 17 | "context" 18 | "strconv" 19 | 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 21 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 22 | awx "github.com/mrcrilly/goawx/client" 23 | ) 24 | 25 | func dataSourceInventoryGroup() *schema.Resource { 26 | return &schema.Resource{ 27 | ReadContext: dataSourceInventoryGroupRead, 28 | Schema: map[string]*schema.Schema{ 29 | "id": &schema.Schema{ 30 | Type: schema.TypeInt, 31 | Optional: true, 32 | Computed: true, 33 | }, 34 | "name": &schema.Schema{ 35 | Type: schema.TypeString, 36 | Optional: true, 37 | Computed: true, 38 | }, 39 | "inventory_id": &schema.Schema{ 40 | Type: schema.TypeInt, 41 | Required: true, 42 | }, 43 | }, 44 | } 45 | } 46 | 47 | func dataSourceInventoryGroupRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 48 | var diags diag.Diagnostics 49 | client := m.(*awx.AWX) 50 | params := make(map[string]string) 51 | if groupName, okName := d.GetOk("name"); okName { 52 | params["name"] = groupName.(string) 53 | } 54 | 55 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 56 | params["id"] = strconv.Itoa(groupID.(int)) 57 | } 58 | 59 | if len(params) == 0 { 60 | return buildDiagnosticsMessage( 61 | "Get: Missing Parameters", 62 | "Please use one of the selectors (name or group_id)", 63 | ) 64 | return diags 65 | } 66 | inventoryID := d.Get("inventory_id").(int) 67 | groups, _, err := client.InventoryGroupService.ListInventoryGroups(inventoryID, params) 68 | if err != nil { 69 | return buildDiagnosticsMessage( 70 | "Get: Fail to fetch Inventory Group", 71 | "Fail to find the group got: %s", 72 | err.Error(), 73 | ) 74 | } 75 | if len(groups) > 1 { 76 | return buildDiagnosticsMessage( 77 | "Get: find more than one Element", 78 | "The Query Returns more than one Group, %d", 79 | len(groups), 80 | ) 81 | return diags 82 | } 83 | 84 | group := groups[0] 85 | d = setInventoryGroupResourceData(d, group) 86 | return diags 87 | } 88 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.pkg.github.com/nolte/vscode-devcontainers/k8s-operator:latest 2 | 3 | # https://github.com/bflad/tfproviderdocs/releases 4 | ENV TFPROVIDERDOCS_VERSION=0.7.0 5 | 6 | # https://github.com/bats-core/bats-core 7 | ENV BATS_VERSION=1.2.0 8 | 9 | USER root 10 | 11 | COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/swagger /usr/local/bin/swagger 12 | COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/terraform /usr/local/bin/terraform 13 | COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/terraform-doc /usr/local/bin/terraform-doc 14 | COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/shellcheck /usr/local/bin/shellcheck 15 | 16 | RUN curl -sSL -k https://github.com/bflad/tfproviderdocs/releases/download/v${TFPROVIDERDOCS_VERSION}/tfproviderdocs_${TFPROVIDERDOCS_VERSION}_linux_amd64.tar.gz -o /tmp/tfproviderdocs.tgz \ 17 | && tar -zxf /tmp/tfproviderdocs.tgz -C /tmp \ 18 | && mv /tmp/tfproviderdocs /usr/local/bin/ 19 | 20 | RUN apk add --update-cache \ 21 | nodejs npm \ 22 | && rm -rf /var/cache/apk/* 23 | 24 | RUN mkdir -p /go/src && chown -R ${USER_UID}:${USER_GID} /go/src \ 25 | && mkdir -p /go/pkg && chown -R ${USER_UID}:${USER_GID} /go/pkg 26 | 27 | RUN curl -sSL -k https://github.com/goreleaser/goreleaser/releases/download/v0.141.0/goreleaser_Linux_x86_64.tar.gz -o /tmp/goreleaser.tgz \ 28 | && tar -zxf /tmp/goreleaser.tgz -C /tmp \ 29 | && mv /tmp/goreleaser /usr/local/bin/ 30 | 31 | 32 | USER ${USERNAME} 33 | 34 | RUN mkdir -p /home/${USERNAME}/.terraform.d/plugins/linux_amd64 35 | 36 | ENV PATH="/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:~/bin:$PATH" 37 | 38 | RUN mkdir "/home/${USERNAME}/.npm-packages" 39 | RUN npm config set prefix "/home/${USERNAME}/.npm-packages" 40 | 41 | 42 | RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.27.0 43 | 44 | RUN curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.3.0 45 | 46 | RUN npm i markdown-spellcheck -g 47 | 48 | RUN curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash 49 | 50 | RUN npm i madr adr-log -g 51 | -------------------------------------------------------------------------------- /awx/data_source_credential_azure_key_vault.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | *TBD* 8 | ``` 9 | 10 | */ 11 | package awx 12 | 13 | import ( 14 | "context" 15 | "fmt" 16 | "strconv" 17 | "time" 18 | 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 21 | awx "github.com/mrcrilly/goawx/client" 22 | ) 23 | 24 | func dataSourceCredentialAzure() *schema.Resource { 25 | return &schema.Resource{ 26 | ReadContext: dataSourceCredentialAzureRead, 27 | Schema: map[string]*schema.Schema{ 28 | "credential_id": &schema.Schema{ 29 | Type: schema.TypeInt, 30 | Required: true, 31 | }, 32 | "name": &schema.Schema{ 33 | Type: schema.TypeString, 34 | Computed: true, 35 | }, 36 | "description": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Computed: true, 39 | }, 40 | "organisation_id": &schema.Schema{ 41 | Type: schema.TypeInt, 42 | Computed: true, 43 | }, 44 | "url": &schema.Schema{ 45 | Type: schema.TypeString, 46 | Computed: true, 47 | }, 48 | "client": &schema.Schema{ 49 | Type: schema.TypeString, 50 | Computed: true, 51 | }, 52 | "secret": &schema.Schema{ 53 | Type: schema.TypeString, 54 | Computed: true, 55 | Sensitive: true, 56 | }, 57 | "tenant": &schema.Schema{ 58 | Type: schema.TypeString, 59 | Computed: true, 60 | }, 61 | }, 62 | } 63 | } 64 | 65 | func dataSourceCredentialAzureRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 66 | var diags diag.Diagnostics 67 | 68 | client := m.(*awx.AWX) 69 | id, _ := d.Get("credential_id").(int) 70 | cred, err := client.CredentialsService.GetCredentialsByID(id, map[string]string{}) 71 | if err != nil { 72 | diags = append(diags, diag.Diagnostic{ 73 | Severity: diag.Error, 74 | Summary: "Unable to fetch credentials", 75 | Detail: fmt.Sprintf("Unable to credentials with id %d: %s", id, err.Error()), 76 | }) 77 | return diags 78 | } 79 | 80 | d.Set("name", cred.Name) 81 | d.Set("description", cred.Description) 82 | d.Set("organisation_id", cred.OrganizationID) 83 | d.Set("url", cred.Inputs["url"]) 84 | d.Set("client", cred.Inputs["client"]) 85 | d.Set("secret", d.Get("secret").(string)) 86 | d.Set("tenant", cred.Inputs["tenant"]) 87 | d.SetId(strconv.FormatInt(time.Now().Unix(), 10)) 88 | 89 | return diags 90 | } 91 | -------------------------------------------------------------------------------- /awx/data_source_inventory.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_inventory" "default" { 8 | name = "private_services" 9 | organisation_id = data.awx_organization.default.id 10 | } 11 | ``` 12 | 13 | */ 14 | package awx 15 | 16 | import ( 17 | "context" 18 | "strconv" 19 | 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 21 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 22 | awx "github.com/mrcrilly/goawx/client" 23 | ) 24 | 25 | func dataSourceInventory() *schema.Resource { 26 | return &schema.Resource{ 27 | ReadContext: dataSourceInventoriesRead, 28 | Schema: map[string]*schema.Schema{ 29 | "id": &schema.Schema{ 30 | Type: schema.TypeInt, 31 | Optional: true, 32 | Computed: true, 33 | }, 34 | "name": &schema.Schema{ 35 | Type: schema.TypeString, 36 | Optional: true, 37 | Computed: true, 38 | }, 39 | "organisation_id": &schema.Schema{ 40 | Type: schema.TypeInt, 41 | Optional: true, 42 | Computed: true, 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | func dataSourceInventoriesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 49 | var diags diag.Diagnostics 50 | client := m.(*awx.AWX) 51 | params := make(map[string]string) 52 | if groupName, okName := d.GetOk("name"); okName { 53 | params["name"] = groupName.(string) 54 | } 55 | 56 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 57 | params["id"] = strconv.Itoa(groupID.(int)) 58 | } 59 | 60 | if organisationID, okIOrgID := d.GetOk("organisation_id"); okIOrgID { 61 | params["organization"] = strconv.Itoa(organisationID.(int)) 62 | } 63 | if len(params) == 0 { 64 | return buildDiagnosticsMessage( 65 | "Get: Missing Parameters", 66 | "Please use one of the selectors (name or group_id)", 67 | ) 68 | return diags 69 | } 70 | inventories, _, err := client.InventoriesService.ListInventories(params) 71 | if err != nil { 72 | return buildDiagnosticsMessage( 73 | "Get: Fail to fetch Inventory Group", 74 | "Fail to find the group got: %s", 75 | err.Error(), 76 | ) 77 | } 78 | if len(inventories) > 1 { 79 | return buildDiagnosticsMessage( 80 | "Get: find more than one Element", 81 | "The Query Returns more than one Group, %d", 82 | len(inventories), 83 | ) 84 | return diags 85 | } 86 | 87 | inventory := inventories[0] 88 | d = setInventoryResourceData(d, inventory) 89 | return diags 90 | } 91 | -------------------------------------------------------------------------------- /awx/data_source_job_template.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_job_template" "default" { 8 | name = "Default" 9 | } 10 | ``` 11 | 12 | */ 13 | package awx 14 | 15 | import ( 16 | "context" 17 | "strconv" 18 | 19 | "log" 20 | 21 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 23 | awx "github.com/mrcrilly/goawx/client" 24 | ) 25 | 26 | func dataSourceJobTemplate() *schema.Resource { 27 | return &schema.Resource{ 28 | ReadContext: dataSourceJobTemplateRead, 29 | Schema: map[string]*schema.Schema{ 30 | "id": &schema.Schema{ 31 | Type: schema.TypeInt, 32 | Optional: true, 33 | Computed: true, 34 | }, 35 | "name": &schema.Schema{ 36 | Type: schema.TypeString, 37 | Optional: true, 38 | Computed: true, 39 | }, 40 | }, 41 | } 42 | } 43 | 44 | func dataSourceJobTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 45 | var diags diag.Diagnostics 46 | client := m.(*awx.AWX) 47 | params := make(map[string]string) 48 | if groupName, okName := d.GetOk("name"); okName { 49 | params["name"] = groupName.(string) 50 | } 51 | 52 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 53 | params["id"] = strconv.Itoa(groupID.(int)) 54 | } 55 | 56 | if len(params) == 0 { 57 | return buildDiagnosticsMessage( 58 | "Get: Missing Parameters", 59 | "Please use one of the selectors (name or group_id)", 60 | ) 61 | } 62 | 63 | jobTemplate, _, err := client.JobTemplateService.ListJobTemplates(params) 64 | 65 | if err != nil { 66 | return buildDiagnosticsMessage( 67 | "Get: Fail to fetch Inventory Group", 68 | "Fail to find the group got: %s", 69 | err.Error(), 70 | ) 71 | } 72 | 73 | for _, template := range jobTemplate { 74 | log.Printf("loop %v", template.Name) 75 | if template.Name == params["name"] { 76 | d = setJobTemplateResourceData(d, template) 77 | return diags 78 | } 79 | } 80 | 81 | if _, okGroupID := d.GetOk("id"); okGroupID { 82 | log.Printf("byid %v", len(jobTemplate)) 83 | if len(jobTemplate) != 1 { 84 | return buildDiagnosticsMessage( 85 | "Get: find more than one Element", 86 | "The Query Returns more than one Group, %d", 87 | len(jobTemplate), 88 | ) 89 | } 90 | d = setJobTemplateResourceData(d, jobTemplate[0]) 91 | return diags 92 | } 93 | return buildDiagnosticsMessage( 94 | "Get: find more than one Element", 95 | "The Query Returns more than one Group, %d", 96 | len(jobTemplate), 97 | ) 98 | } 99 | -------------------------------------------------------------------------------- /awx/data_source_workflow_job_template.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_workflow_job_template" "default" { 8 | name = "Default" 9 | } 10 | ``` 11 | 12 | */ 13 | package awx 14 | 15 | import ( 16 | "context" 17 | "strconv" 18 | 19 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 21 | awx "github.com/mrcrilly/goawx/client" 22 | ) 23 | 24 | func dataSourceWorkflowJobTemplate() *schema.Resource { 25 | return &schema.Resource{ 26 | ReadContext: dataSourceWorkflowJobTemplateRead, 27 | Schema: map[string]*schema.Schema{ 28 | "id": &schema.Schema{ 29 | Type: schema.TypeInt, 30 | Optional: true, 31 | Computed: true, 32 | }, 33 | "name": &schema.Schema{ 34 | Type: schema.TypeString, 35 | Optional: true, 36 | Computed: true, 37 | }, 38 | }, 39 | } 40 | } 41 | 42 | func dataSourceWorkflowJobTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 43 | var diags diag.Diagnostics 44 | client := m.(*awx.AWX) 45 | params := make(map[string]string) 46 | if groupName, okName := d.GetOk("name"); okName { 47 | params["name"] = groupName.(string) 48 | } 49 | 50 | if groupID, okGroupID := d.GetOk("id"); okGroupID { 51 | params["id"] = strconv.Itoa(groupID.(int)) 52 | } 53 | 54 | if len(params) == 0 { 55 | return buildDiagnosticsMessage( 56 | "Get: Missing Parameters", 57 | "Please use one of the selectors (name or group_id)", 58 | ) 59 | } 60 | workflowJobTemplate, _, err := client.WorkflowJobTemplateService.ListWorkflowJobTemplates(params) 61 | if err != nil { 62 | return buildDiagnosticsMessage( 63 | "Get: Fail to fetch Inventory Group", 64 | "Fail to find the group got: %s", 65 | err.Error(), 66 | ) 67 | } 68 | if groupName, okName := d.GetOk("name"); okName { 69 | for _, template := range workflowJobTemplate { 70 | if template.Name == groupName { 71 | d = setWorkflowJobTemplateResourceData(d, template) 72 | return diags 73 | } 74 | } 75 | } 76 | if _, okGroupID := d.GetOk("id"); okGroupID { 77 | if len(workflowJobTemplate) != 1 { 78 | return buildDiagnosticsMessage( 79 | "Get: find more than one Element", 80 | "The Query Returns more than one Group, %d", 81 | len(workflowJobTemplate), 82 | ) 83 | } 84 | d = setWorkflowJobTemplateResourceData(d, workflowJobTemplate[0]) 85 | return diags 86 | } 87 | return buildDiagnosticsMessage( 88 | "Get: find more than one Element", 89 | "The Query Returns more than one Group, %d", 90 | len(workflowJobTemplate), 91 | ) 92 | } 93 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "terraform-provider-harbor", 3 | "dockerComposeFile": [ 4 | "docker-compose.yml" 5 | ], 6 | "service": "vscode", 7 | "runServices": [ 8 | "vscode", 9 | ], 10 | "mounts": [ 11 | "source=terraform-awx-vol,target=/home/vscode/.vscode-server/extensions,type=volume", 12 | // And/or for VS Code Insiders 13 | "source=terraform-awx-vol-insiders,target=/home/vscode/.vscode-server-insiders/extensions,type=volume", 14 | ], 15 | "shutdownAction": "stopCompose", 16 | "postCreateCommand": "chmod -R 700 .git", 17 | "workspaceFolder": "/go/src/github.com/mrcrilly/terraform-provider-awx", 18 | // "overrideCommand": "", 19 | "extensions": [ 20 | // General backend 21 | "mohsen1.prettify-json", 22 | "redhat.vscode-yaml", // Kubernetes and Kedge syntax support 23 | // Go 24 | "ms-vscode.go", 25 | "hbenl.vscode-test-explorer", 26 | "ethan-reesor.vscode-go-test-adapter", 27 | // Console 28 | "IBM.output-colorizer", 29 | // Git 30 | "eamodio.gitlens", 31 | "mhutchie.git-graph", 32 | // Other linters 33 | "davidanson.vscode-markdownlint", 34 | "ms-azuretools.vscode-docker", 35 | // Other helpers 36 | "shardulm94.trailing-spaces", 37 | "Gruntfuggly.todo-tree", 38 | "bierner.emojisense", 39 | "stkb.rewrap", // rewrap comments after n characters on one line 40 | // Other 41 | "jrebocho.vscode-random", // generate random values 42 | "alefragnani.Bookmarks", 43 | "quicktype.quicktype", // Paste JSON as code 44 | "spikespaz.vscode-smoothtype", // smooth cursor animation 45 | "vscode-icons-team.vscode-icons", 46 | // markdown 47 | "jebbs.markdown-extended", 48 | "bierner.github-markdown-preview", 49 | "HashiCorp.terraform", 50 | "ms-kubernetes-tools.kind-vscode", 51 | "ms-kubernetes-tools.vscode-kubernetes-tools", 52 | "jetmartin.bats", 53 | "EditorConfig.EditorConfig", 54 | "lonefy.vscode-js-css-html-formatter", 55 | "richie5um2.vscode-statusbar-json-path", 56 | ], 57 | "settings": { 58 | // General settings 59 | "files.eol": "\n", 60 | "files.encoding": "utf8", 61 | "editor.renderWhitespace": "all", 62 | // Docker 63 | "remote.extensionKind": { 64 | "ms-azuretools.vscode-docker": "workspace" 65 | }, 66 | "[makefile]": { 67 | "editor.insertSpaces": false, 68 | "editor.detectIndentation": false 69 | }, 70 | "go.useLanguageServer": true, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /awx/resource_job_template_credential.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "awx_job_template_credentials" "baseconfig" { 8 | job_template_id = awx_job_template.baseconfig.id 9 | credential_id = awx_credential_machine.pi_connection.id 10 | } 11 | ``` 12 | 13 | */ 14 | package awx 15 | 16 | import ( 17 | "context" 18 | "fmt" 19 | "strconv" 20 | 21 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 23 | awx "github.com/mrcrilly/goawx/client" 24 | ) 25 | 26 | func resourceJobTemplateCredentials() *schema.Resource { 27 | return &schema.Resource{ 28 | CreateContext: resourceJobTemplateCredentialsCreate, 29 | DeleteContext: resourceJobTemplateCredentialsDelete, 30 | ReadContext: resourceJobTemplateCredentialsRead, 31 | 32 | Schema: map[string]*schema.Schema{ 33 | 34 | "job_template_id": &schema.Schema{ 35 | Type: schema.TypeInt, 36 | Required: true, 37 | ForceNew: true, 38 | }, 39 | "credential_id": &schema.Schema{ 40 | Type: schema.TypeInt, 41 | Required: true, 42 | ForceNew: true, 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | func resourceJobTemplateCredentialsCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 49 | var diags diag.Diagnostics 50 | client := m.(*awx.AWX) 51 | awxService := client.JobTemplateService 52 | jobTemplateID := d.Get("job_template_id").(int) 53 | _, err := awxService.GetJobTemplateByID(jobTemplateID, make(map[string]string)) 54 | if err != nil { 55 | return buildDiagNotFoundFail("job template", jobTemplateID, err) 56 | } 57 | 58 | result, err := awxService.AssociateCredentials(jobTemplateID, map[string]interface{}{ 59 | "id": d.Get("credential_id").(int), 60 | }, map[string]string{}) 61 | 62 | if err != nil { 63 | return buildDiagnosticsMessage("Create: JobTemplate not AssociateCredentials", "Fail to add credentials with Id %v, for Template ID %v, got error: %s", d.Get("credential_id").(int), jobTemplateID, err.Error()) 64 | } 65 | 66 | d.SetId(strconv.Itoa(result.ID)) 67 | return diags 68 | } 69 | 70 | func resourceJobTemplateCredentialsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 71 | var diags diag.Diagnostics 72 | return diags 73 | } 74 | 75 | func resourceJobTemplateCredentialsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 76 | var diags diag.Diagnostics 77 | client := m.(*awx.AWX) 78 | awxService := client.JobTemplateService 79 | jobTemplateID := d.Get("job_template_id").(int) 80 | res, err := awxService.GetJobTemplateByID(jobTemplateID, make(map[string]string)) 81 | if err != nil { 82 | return buildDiagNotFoundFail("job template", jobTemplateID, err) 83 | } 84 | 85 | _, err = awxService.DisAssociateCredentials(res.ID, map[string]interface{}{ 86 | "id": d.Get("credential_id").(int), 87 | }, map[string]string{}) 88 | if err != nil { 89 | return buildDiagDeleteFail("JobTemplate DisAssociateCredentials", fmt.Sprintf("DisAssociateCredentials %v, from JobTemplateID %v got %s ", d.Get("credential_id").(int), d.Get("job_template_id").(int), err.Error())) 90 | } 91 | 92 | d.SetId("") 93 | return diags 94 | } 95 | -------------------------------------------------------------------------------- /examples/k8s/base/files/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBL0vIUMP 3 | kN9kiizE7k7y2SAAAAEAAAAAEAAAIXAAAAB3NzaC1yc2EAAAADAQABAAACAQDFfyuCPV/U 4 | 92QRS9zRXPJhY1DUZQHf3fc/qnkUxY1RQ7492tcJoOhFoTIyonq6uS8WJFSFADPcY2lhXd 5 | tRsLZrIqgVMNNvN5Hv8QMI4/WZsPb7juGdrBPogQcX3xpEJtD5tJOptHlnY1StCLw54Rcs 6 | ysCPPBI/yQNF5yM7jXgF+75O0a2NRhvTH0V1CxhgPuiz9Io1HZqrw7Rv9uYhpTh1XaZYhf 7 | pWAeAEbHvHG+HBlm27NYY2Oolr5vdu8mfK7w+A0NMLCu5cuK6OKIOMHG09IXKuO7SfZelE 8 | DPYios1Ubm/oDqfb1eiM71ZoErMzz2RxRZ8E7wT++V3Yv5/yPS8v0nSIKFco/2NpC4IFSb 9 | PZG2AF6roRNGtTtTXErxTZbgOL2VPOhCLiJx1H+a4wq5ksnb3zUq7+mgSPtI6zmcZ2Up9U 10 | bqvAFfDuF1EJ5MoYMakLYq7SGImPraUxnOifUtMvhI02j1NDlsDxM+Z2nvZvQepxYt6G86 11 | ShbJEHxhlJ8SpgCO3JTfW94zkMLE4UNalPoB2WgIQr6RUdlDGbfbRjHWS2o8X/AsejVJQe 12 | 78gge6GUKCrKW0y1mKUqpu1XgSJhEAl/fnDeQ347OU5/5qePUBmqP1fKGJvgWcMWnVEiBf 13 | TiAGJY7FkIvPCjIohUzzbkL4CG77NF/hSIMhQWS90GVwAAB1CAelqeS4W+++I2vsb9soz1 14 | LB2bUe8abvWq23fpDvC/B7clE/OJL/2zHfuW6oVsSdCYHy6R3W6CYbf9ncA+S9XnNXHsyB 15 | 4xgZGoc0HAoX2CqJwrcqkwE25/mLJJV+TxeEu0/68arCbs63iEY199JN7RfH0dHLgKWLBS 16 | /11LuBjTMLXu1Y6j4CPnNR3Rnwg7di2Mku8ZRy9w/Y9nFpNOY8meeywUXfKg/KAgpcvJ1G 17 | so5BVrHb16sKOzGjuGZVt8dQ1yolc2kuWl1mgBddxXR261Nq/v4GPUYrMcdmTVD2gBp9Wg 18 | 9TNDH+xt4LJv3FMZVKqW3nfVp596FWIjYYxQH3F+X/BILBElfApjC+WdXAKsoRHzmJK2xu 19 | wc1TGmnTdblF+egcc7roegSCiBT31Meg3ICtqIz5zhthG0DHQTAAcAa8ZomQp5c63HJI/d 20 | aRvqicKef5JybdxrmVmeoABQ2I7HSysvZ9+6HR0hIp/7Axi/WalLzcF/qK0wRtQwN1rXQg 21 | VkVPvHgED/faRQo424QQ62O/wF6TI43OlJbzPbUyN2Sr+GJBcajUOyC7u7lkNCr4epTzoy 22 | bpLapZAw+dpdSBMXZ3ycnPh5qNJH5d8mE9qI54OOlVcEZovSk3xxDE+RwyqKOTNbzeuHTA 23 | yIdn5/mV16ZR/d6vcsnCJBR1Zx+gSozpjiafEaVyA5MBM6qVYLCbqAYVH5mcVpzoaI32kF 24 | KSK6G2tObaCRQpEb78c6iIzbAnVMknp1Cihg1pCbRFeFq0yO3a1FoWivW84IRgyv2T08aT 25 | jfP99YfdqPdaRuzoaytOnG7/PiFBQrOu5b2elNRtNOqL1NYEFSDcY0bAHBRt3qRnfFM9PT 26 | wYsx4J6m5klbzUw4OE6J8ItXRgTth4VafA5VYihUTj8pulNfKK98Q9y4Td0fnYod7P5JMF 27 | AicjLzSjsEiRt4kdg650o0MmTj6WgPurbYot67zh0aLopjLmPoN7xEUcyYI5X3Ye+yIT6/ 28 | szoJgwkKFLw5ltnMeYk5gn1kYLuOfuotCvqeAKIxpBPedrf31TH8xMyELRt0BYXAek2cKH 29 | FndkPIP3b0S12mtqeaDjRiqdeTsli07J5R1lZMvASTANYbREdDzXtx0oqOy2YB9UApOdxF 30 | ymsxf1pf/vOT4NCeS3OtFFQkyMPjYJYK3HkIenthMYyk2vQYfX18+t+WyMo8dfjY8BvgZ6 31 | /srRuA89bsk4AZ5UWu0MmUFqQx1HEciDU3Dg8MJwH2cnp8rE2bvWURXO8Q+B16vpW4Jo8P 32 | U2DZFSUxEk9U/3kliBMqA0kAey1xLyiK5fllOprCJDnl9G1/dNKS1QiOHFgvldlytdFG14 33 | CpqUcFot0EcRD2f5uqPkOC0UaKd3eGVTrhTMzv6MYvlDMsrMWz4zV/iGrRqHcl0nxNcI1A 34 | pzv/qtAT434+A6A0uIKoLAf6JixDDmWyJ3RGEUri3u6WpDXtWMV2fYs3DZfxp5uoT2EPcK 35 | yleBUd6F6m1Jji/OMfHjT+4gyMuZ6Ciih6LVfdo05yFf2uSnAC3knWrbiP+LdIQM7rpxHP 36 | 0wiAwWJc5vBo0tLQwty4vCOQq3vsCd19AmK2iAlxej7uuau+LW3obgGU4Hs2xDTjBV5pK5 37 | 3SfucFcyyoULpFuoGcRokDoVnTc/x9I5OGRz+R+8jFIyDvhHZG6fOa9wqDIuM2yZ7ICREc 38 | Eaw6SdymRJYIiOvIetikmyjGD2a6XTl39oCv7XqB4j6Ofvi9iKm3kAf1AOmGL70pMS7BJV 39 | B7rEjyVp9fyAh/WozDPghySka/c1LGcs8cLsQUippwX225kYEx7PYraMDenruZzA/VEQyB 40 | 1vpi1V/TZ1PMgFZlhUzammNM4W3du1U5LdjdE1/fl/XoFg3I3BYqxlt/WXQ0u/fMIDbxgf 41 | mLTVYd0YtAhOInjC9QDH1tf+c1RiSFXJb8P+cMxNMcouov9YzXfcTGWDgjrlHgjewxyzVp 42 | VFkTVFf+IqeQCbIaR0BiO/8r9w75IupG9VW6p5QoBQHx4bS6ZGRSVYKuG/8wQGkNQCk/Ka 43 | P/vBtpmZRntS2+A46RpeZQ90dewthxQZbgl0z8gdkgy14NGFTy6qvJAKl+7vqdcrIRGx81 44 | 8wOT8Y6psps0Z1zMO4Skz34lpG0eX8qHpE4M1ou9Zv9CjGzSCpk9VfBl3In1vOgIHJg5QJ 45 | AsVJ62QwMjbxtPXpWtdTQVWn6RPJfcwq2fkVEv4LuTKOKR4h/vF2Hfex/7xF65HyAcxbal 46 | f9uG01ZU4Vuf1zY4XQoRoBYCbo/FEsT1LJy9kKZE02lhwc8x+SbUhCHvOQfM/MdifogGnY 47 | KXhQ2pS6SBoWDNR4H/yhr8r/EQFaI0Nj9CFC+ZSsaAeLMO/8eAjMnfYOmhWTTV/bkQ2+wS 48 | W4L3wNcLQuZKAGrv203ZcwNBBivB0FhmKTLSKwQOD5gHg4SApukc6NWIcPm5+uh/sJcAbO 49 | kTYuyK8d4/WH/5UKUASbRLuFM= 50 | -----END OPENSSH PRIVATE KEY----- 51 | -------------------------------------------------------------------------------- /examples/k8s/base/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "awx_organization" "default" { 3 | name = "acc-test" 4 | } 5 | 6 | resource "awx_inventory" "default" { 7 | name = "acc-test" 8 | organisation_id = awx_organization.default.id 9 | variables = < 0 { 135 | attributes = append(attributes, attrs...) 136 | } 137 | } 138 | } 139 | 140 | sort.Strings(requiredArgs) 141 | sort.Strings(optionalArgs) 142 | sort.Strings(attributes) 143 | 144 | requiredArgs = append(requiredArgs, optionalArgs...) 145 | data["arguments"] = strings.Join(requiredArgs, "\n") 146 | if len(subStruct) > 0 { 147 | data["arguments"] += "\n" + strings.Join(subStruct, "\n") 148 | } 149 | data["attributes"] = strings.Join(attributes, "\n") 150 | dtypePath := "" 151 | if dtype == "data_source" { 152 | dtypePath = "data-sources" 153 | } else if dtype == "resource" { 154 | dtypePath = "resources" 155 | } 156 | fname = fmt.Sprintf("%s/%s/%s.md", docRoot, dtypePath, data["resource"]) 157 | fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 158 | if err != nil { 159 | log.Printf("[FAIL!]open file %s failed: %s", fname, err) 160 | return 161 | } 162 | 163 | defer func() { 164 | if e := fd.Close(); e != nil { 165 | log.Printf("[FAIL!]close file %s failed: %s", fname, e) 166 | } 167 | }() 168 | t := template.Must(template.New("t").Parse(docTPL)) 169 | err = t.Execute(fd, data) 170 | if err != nil { 171 | log.Printf("[FAIL!]write file %s failed: %s", fname, err) 172 | return 173 | } 174 | 175 | log.Printf("[SUCC.]write doc to file success: %s", fname) 176 | } 177 | 178 | // getAttributes get attributes from schema 179 | func getAttributes(step int, k string, v *schema.Schema) []string { 180 | attributes := []string{} 181 | ident := strings.Repeat(" ", step*2) 182 | 183 | //if v.Description == "" { 184 | // return attributes 185 | //} 186 | 187 | if v.Computed { 188 | if _, ok := v.Elem.(*schema.Resource); ok { 189 | listAttributes := []string{} 190 | for kk, vv := range v.Elem.(*schema.Resource).Schema { 191 | attrs := getAttributes(step+1, kk, vv) 192 | if len(attrs) > 0 { 193 | listAttributes = append(listAttributes, attrs...) 194 | } 195 | } 196 | slistAttributes := "" 197 | sort.Strings(listAttributes) 198 | if len(listAttributes) > 0 { 199 | slistAttributes = "\n" + strings.Join(listAttributes, "\n") 200 | } 201 | attributes = append(attributes, fmt.Sprintf("%s* `%s` - %s%s", ident, k, v.Description, slistAttributes)) 202 | } else { 203 | attributes = append(attributes, fmt.Sprintf("%s* `%s` - %s", ident, k, v.Description)) 204 | } 205 | } 206 | 207 | return attributes 208 | } 209 | 210 | // getFileDescription get description from go file 211 | func getFileDescription(fname string) (string, error) { 212 | fset := token.NewFileSet() 213 | 214 | parsedAst, err := parser.ParseFile(fset, fname, nil, parser.ParseComments) 215 | if err != nil { 216 | return "", err 217 | } 218 | 219 | return parsedAst.Doc.Text(), nil 220 | } 221 | 222 | // getSubStruct get sub structure from go file 223 | func getSubStruct(step int, k string, v *schema.Schema) []string { 224 | subStructs := []string{} 225 | 226 | if v.Description == "" { 227 | return subStructs 228 | } 229 | 230 | if v.Type == schema.TypeMap || v.Type == schema.TypeList || v.Type == schema.TypeSet { 231 | if _, ok := v.Elem.(*schema.Resource); ok { 232 | subStructs = append(subStructs, fmt.Sprintf("\nThe `%s` object supports the following:\n", k)) 233 | requiredArgs := []string{} 234 | optionalArgs := []string{} 235 | attributes := []string{} 236 | 237 | var keys []string 238 | for kk := range v.Elem.(*schema.Resource).Schema { 239 | keys = append(keys, kk) 240 | } 241 | sort.Strings(keys) 242 | for _, kk := range keys { 243 | vv := v.Elem.(*schema.Resource).Schema[kk] 244 | if vv.Description == "" { 245 | vv.Description = "************************* Please input Description for Schema ************************* " 246 | } 247 | if vv.Required { 248 | opt := "Required" 249 | if vv.ForceNew { 250 | opt += ", ForceNew" 251 | } 252 | requiredArgs = append(requiredArgs, fmt.Sprintf("* `%s` - (%s) %s", kk, opt, vv.Description)) 253 | } else if vv.Optional { 254 | opt := "Optional" 255 | if vv.ForceNew { 256 | opt += ", ForceNew" 257 | } 258 | optionalArgs = append(optionalArgs, fmt.Sprintf("* `%s` - (%s) %s", kk, opt, vv.Description)) 259 | } else { 260 | attrs := getAttributes(0, kk, vv) 261 | if len(attrs) > 0 { 262 | attributes = append(attributes, attrs...) 263 | } 264 | } 265 | } 266 | sort.Strings(requiredArgs) 267 | subStructs = append(subStructs, requiredArgs...) 268 | sort.Strings(optionalArgs) 269 | subStructs = append(subStructs, optionalArgs...) 270 | sort.Strings(attributes) 271 | subStructs = append(subStructs, attributes...) 272 | 273 | for _, kk := range keys { 274 | vv := v.Elem.(*schema.Resource).Schema[kk] 275 | subStructs = append(subStructs, getSubStruct(step+1, kk, vv)...) 276 | } 277 | } 278 | } 279 | return subStructs 280 | } 281 | -------------------------------------------------------------------------------- /awx/resource_workflow_job_template.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "awx_workflow_job_template" "default" { 8 | name = "workflow-job" 9 | organisation_id = var.organisation_id 10 | inventory_id = awx_inventory.default.id 11 | } 12 | ``` 13 | 14 | */ 15 | package awx 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | "log" 21 | "strconv" 22 | 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 24 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 25 | awx "github.com/mrcrilly/goawx/client" 26 | ) 27 | 28 | func resourceWorkflowJobTemplate() *schema.Resource { 29 | return &schema.Resource{ 30 | CreateContext: resourceWorkflowJobTemplateCreate, 31 | ReadContext: resourceWorkflowJobTemplateRead, 32 | UpdateContext: resourceWorkflowJobTemplateUpdate, 33 | DeleteContext: resourceWorkflowJobTemplateDelete, 34 | 35 | Schema: map[string]*schema.Schema{ 36 | "name": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Required: true, 39 | Description: "Name of this workflow job template. (string, required)", 40 | }, 41 | "description": &schema.Schema{ 42 | Type: schema.TypeString, 43 | Optional: true, 44 | Default: "", 45 | Description: "Optional description of this workflow job template.", 46 | }, 47 | "variables": &schema.Schema{ 48 | Type: schema.TypeString, 49 | Optional: true, 50 | Default: "", 51 | Description: "", 52 | StateFunc: normalizeJsonYaml, 53 | }, 54 | "organisation_id": &schema.Schema{ 55 | Type: schema.TypeInt, 56 | Optional: true, 57 | Default: 0, 58 | Description: "The organization used to determine access to this template. (id, default=``)", 59 | }, 60 | "survey_enabled": &schema.Schema{ 61 | Type: schema.TypeBool, 62 | Optional: true, 63 | Default: false, 64 | }, 65 | "allow_simultaneous": &schema.Schema{ 66 | Type: schema.TypeBool, 67 | Optional: true, 68 | Default: false, 69 | }, 70 | "ask_variables_on_launch": &schema.Schema{ 71 | Type: schema.TypeBool, 72 | Optional: true, 73 | Default: false, 74 | }, 75 | "inventory_id": &schema.Schema{ 76 | Type: schema.TypeInt, 77 | Optional: true, 78 | Description: "Inventory applied as a prompt, assuming job template prompts for inventory.", 79 | }, 80 | "limit": &schema.Schema{ 81 | Type: schema.TypeString, 82 | Optional: true, 83 | Default: "", 84 | }, 85 | "scm_branch": &schema.Schema{ 86 | Type: schema.TypeString, 87 | Optional: true, 88 | Default: "", 89 | }, 90 | "ask_inventory_on_launch": &schema.Schema{ 91 | Type: schema.TypeBool, 92 | Optional: true, 93 | Default: false, 94 | }, 95 | "ask_scm_branch_on_launch": &schema.Schema{ 96 | Type: schema.TypeBool, 97 | Optional: true, 98 | Default: false, 99 | }, 100 | "ask_limit_on_launch": &schema.Schema{ 101 | Type: schema.TypeBool, 102 | Optional: true, 103 | Default: false, 104 | }, 105 | "webhook_service": &schema.Schema{ 106 | Type: schema.TypeString, 107 | Optional: true, 108 | Default: "", 109 | }, 110 | "webhook_credential": &schema.Schema{ 111 | Type: schema.TypeString, 112 | Optional: true, 113 | Default: "", 114 | }, 115 | }, 116 | //Importer: &schema.ResourceImporter{ 117 | // State: schema.ImportStatePassthrough, 118 | //}, 119 | // 120 | //Timeouts: &schema.ResourceTimeout{ 121 | // Create: schema.DefaultTimeout(1 * time.Minute), 122 | // Update: schema.DefaultTimeout(1 * time.Minute), 123 | // Delete: schema.DefaultTimeout(1 * time.Minute), 124 | //}, 125 | } 126 | } 127 | 128 | func resourceWorkflowJobTemplateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 129 | var diags diag.Diagnostics 130 | client := m.(*awx.AWX) 131 | awxService := client.WorkflowJobTemplateService 132 | 133 | result, err := awxService.CreateWorkflowJobTemplate(map[string]interface{}{ 134 | "name": d.Get("name").(string), 135 | "description": d.Get("description").(string), 136 | "organisation": d.Get("organisation_id").(int), 137 | "inventory": d.Get("inventory_id").(int), 138 | "extra_vars": d.Get("variables").(string), 139 | "survey_enabled": d.Get("survey_enabled").(bool), 140 | "allow_simultaneous": d.Get("allow_simultaneous").(bool), 141 | "ask_variables_on_launch": d.Get("ask_variables_on_launch").(bool), 142 | "limit": d.Get("limit").(string), 143 | "scm_branch": d.Get("scm_branch").(string), 144 | "ask_inventory_on_launch": d.Get("ask_inventory_on_launch").(bool), 145 | "ask_scm_branch_on_launch": d.Get("ask_scm_branch_on_launch").(bool), 146 | "ask_limit_on_launch": d.Get("ask_limit_on_launch").(bool), 147 | "webhook_service": d.Get("webhook_service").(string), 148 | "webhook_credential": d.Get("webhook_credential").(string), 149 | }, map[string]string{}) 150 | if err != nil { 151 | log.Printf("Fail to Create Template %v", err) 152 | diags = append(diags, diag.Diagnostic{ 153 | Severity: diag.Error, 154 | Summary: "Unable to create WorkflowJobTemplate", 155 | Detail: fmt.Sprintf("WorkflowJobTemplate with name %s faild to create %s", d.Get("name").(string), err.Error()), 156 | }) 157 | return diags 158 | } 159 | 160 | d.SetId(strconv.Itoa(result.ID)) 161 | return resourceWorkflowJobTemplateRead(ctx, d, m) 162 | } 163 | 164 | func resourceWorkflowJobTemplateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 165 | var diags diag.Diagnostics 166 | client := m.(*awx.AWX) 167 | awxService := client.WorkflowJobTemplateService 168 | id, diags := convertStateIDToNummeric("Update WorkflowJobTemplate", d) 169 | if diags.HasError() { 170 | return diags 171 | } 172 | 173 | params := make(map[string]string) 174 | _, err := awxService.GetWorkflowJobTemplateByID(id, params) 175 | if err != nil { 176 | return buildDiagNotFoundFail("job Workflow template", id, err) 177 | } 178 | 179 | _, err = awxService.UpdateWorkflowJobTemplate(id, map[string]interface{}{ 180 | "name": d.Get("name").(string), 181 | "description": d.Get("description").(string), 182 | "organisation": d.Get("organisation_id").(int), 183 | "inventory": d.Get("inventory_id").(int), 184 | "extra_vars": d.Get("variables").(string), 185 | "survey_enabled": d.Get("survey_enabled").(bool), 186 | "allow_simultaneous": d.Get("allow_simultaneous").(bool), 187 | "ask_variables_on_launch": d.Get("ask_variables_on_launch").(bool), 188 | "limit": d.Get("limit").(string), 189 | "scm_branch": d.Get("scm_branch").(string), 190 | "ask_inventory_on_launch": d.Get("ask_inventory_on_launch").(bool), 191 | "ask_scm_branch_on_launch": d.Get("ask_scm_branch_on_launch").(bool), 192 | "ask_limit_on_launch": d.Get("ask_limit_on_launch").(bool), 193 | "webhook_service": d.Get("webhook_service").(string), 194 | "webhook_credential": d.Get("webhook_credential").(string), 195 | }, map[string]string{}) 196 | if err != nil { 197 | diags = append(diags, diag.Diagnostic{ 198 | Severity: diag.Error, 199 | Summary: "Unable to update WorkflowJobTemplate", 200 | Detail: fmt.Sprintf("WorkflowJobTemplate with name %s in the project id %d faild to update %s", d.Get("name").(string), d.Get("project_id").(int), err.Error()), 201 | }) 202 | return diags 203 | } 204 | 205 | return resourceWorkflowJobTemplateRead(ctx, d, m) 206 | } 207 | 208 | func resourceWorkflowJobTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 209 | var diags diag.Diagnostics 210 | client := m.(*awx.AWX) 211 | awxService := client.WorkflowJobTemplateService 212 | id, diags := convertStateIDToNummeric("Read WorkflowJobTemplate", d) 213 | if diags.HasError() { 214 | return diags 215 | } 216 | 217 | res, err := awxService.GetWorkflowJobTemplateByID(id, make(map[string]string)) 218 | if err != nil { 219 | return buildDiagNotFoundFail("workflow job template", id, err) 220 | 221 | } 222 | d = setWorkflowJobTemplateResourceData(d, res) 223 | return nil 224 | } 225 | 226 | func resourceWorkflowJobTemplateDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 227 | client := m.(*awx.AWX) 228 | awxService := client.WorkflowJobTemplateService 229 | id, diags := convertStateIDToNummeric(diagElementHostTitle, d) 230 | if diags.HasError() { 231 | return diags 232 | } 233 | 234 | if _, err := awxService.DeleteWorkflowJobTemplate(id); err != nil { 235 | return buildDiagDeleteFail( 236 | diagElementHostTitle, 237 | fmt.Sprintf("id %v, got %s ", 238 | id, err.Error())) 239 | } 240 | d.SetId("") 241 | return nil 242 | } 243 | 244 | func setWorkflowJobTemplateResourceData(d *schema.ResourceData, r *awx.WorkflowJobTemplate) *schema.ResourceData { 245 | 246 | d.Set("name", r.Name) 247 | d.Set("description", r.Description) 248 | d.Set("organisation_id", strconv.Itoa(r.Organization)) 249 | d.Set("inventory_id", strconv.Itoa(r.Inventory)) 250 | d.Set("survey_enabled", r.SurveyEnabled) 251 | d.Set("allow_simultaneous", r.AllowSimultaneous) 252 | d.Set("ask_variables_on_launch", r.AskVariablesOnLaunch) 253 | d.Set("limit", r.Limit) 254 | d.Set("scm_branch", r.ScmBranch) 255 | d.Set("ask_inventory_on_launch", r.AskInventoryOnLaunch) 256 | d.Set("ask_scm_branch_on_launch", r.AskScmBranchOnLaunch) 257 | d.Set("ask_limit_on_launch", r.AskLimitOnLaunch) 258 | d.Set("webhook_service", r.WebhookService) 259 | d.Set("webhook_credential", r.WebhookCredential) 260 | d.Set("variables", normalizeJsonYaml(r.ExtraVars)) 261 | 262 | d.SetId(strconv.Itoa(r.ID)) 263 | return d 264 | } 265 | -------------------------------------------------------------------------------- /awx/resource_project.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_organization" "default" { 8 | name = "Default" 9 | } 10 | 11 | resource "awx_project" "base_service_config" { 12 | name = "base-service-configuration" 13 | scm_type = "git" 14 | scm_url = "https://github.com/nolte/ansible_playbook-baseline-online-server" 15 | scm_branch = "feature/centos8-v2" 16 | scm_update_on_launch = true 17 | organisation_id = data.awx_organization.default.id 18 | } 19 | ``` 20 | 21 | */ 22 | package awx 23 | 24 | import ( 25 | "context" 26 | "fmt" 27 | "strconv" 28 | "time" 29 | 30 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 31 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 32 | awx "github.com/mrcrilly/goawx/client" 33 | ) 34 | 35 | func resourceProject() *schema.Resource { 36 | return &schema.Resource{ 37 | CreateContext: resourceProjectCreate, 38 | ReadContext: resourceProjectRead, 39 | DeleteContext: resourceProjectDelete, 40 | UpdateContext: resourceProjectUpdate, 41 | 42 | Schema: map[string]*schema.Schema{ 43 | "name": &schema.Schema{ 44 | Type: schema.TypeString, 45 | Required: true, 46 | Description: "Name of this project", 47 | }, 48 | 49 | "description": &schema.Schema{ 50 | Type: schema.TypeString, 51 | Optional: true, 52 | Default: "", 53 | Description: "Optional description of this project.", 54 | }, 55 | 56 | "local_path": &schema.Schema{ 57 | Type: schema.TypeString, 58 | Optional: true, 59 | Default: "", 60 | Description: "Local path (relative to PROJECTS_ROOT) containing playbooks and related files for this project.", 61 | }, 62 | 63 | "scm_type": &schema.Schema{ 64 | Type: schema.TypeString, 65 | Required: true, 66 | Description: "One of \"\" (manual), git, hg, svn", 67 | }, 68 | 69 | "scm_url": &schema.Schema{ 70 | Type: schema.TypeString, 71 | Optional: true, 72 | Default: "", 73 | Description: "", 74 | }, 75 | "scm_credential_id": &schema.Schema{ 76 | Type: schema.TypeInt, 77 | Optional: true, 78 | Description: "Numeric ID of the scm used credential", 79 | }, 80 | "scm_branch": &schema.Schema{ 81 | Type: schema.TypeString, 82 | Optional: true, 83 | Default: "", 84 | Description: "Specific branch, tag or commit to checkout.", 85 | }, 86 | "scm_clean": &schema.Schema{ 87 | Type: schema.TypeBool, 88 | Optional: true, 89 | Default: false, 90 | }, 91 | "scm_delete_on_update": &schema.Schema{ 92 | Type: schema.TypeBool, 93 | Optional: true, 94 | Default: false, 95 | }, 96 | "organisation_id": &schema.Schema{ 97 | Type: schema.TypeInt, 98 | Required: true, 99 | Description: "Numeric ID of the project organization", 100 | }, 101 | "scm_update_on_launch": &schema.Schema{ 102 | Type: schema.TypeBool, 103 | Optional: true, 104 | Default: false, 105 | }, 106 | "scm_update_cache_timeout": &schema.Schema{ 107 | Type: schema.TypeInt, 108 | Optional: true, 109 | Default: 0, 110 | }, 111 | }, 112 | Importer: &schema.ResourceImporter{ 113 | State: schema.ImportStatePassthrough, 114 | }, 115 | 116 | Timeouts: &schema.ResourceTimeout{ 117 | Create: schema.DefaultTimeout(1 * time.Minute), 118 | Update: schema.DefaultTimeout(1 * time.Minute), 119 | Delete: schema.DefaultTimeout(5 * time.Minute), 120 | }, 121 | } 122 | } 123 | 124 | func resourceProjectCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 125 | client := m.(*awx.AWX) 126 | awxService := client.ProjectService 127 | 128 | orgID := d.Get("organisation_id").(int) 129 | projectName := d.Get("name").(string) 130 | _, res, err := awxService.ListProjects(map[string]string{ 131 | "name": projectName, 132 | "organization": strconv.Itoa(orgID), 133 | }, 134 | ) 135 | if err != nil { 136 | return buildDiagnosticsMessage("Create: Fail to find Project", "Fail to find Project %s Organisation ID %v, %s", projectName, orgID, err.Error()) 137 | } 138 | if len(res.Results) >= 1 { 139 | return buildDiagnosticsMessage("Create: Allways exist", "Project with name %s already exists in the Organisation ID %v", projectName, orgID) 140 | } 141 | credentials := "" 142 | if d.Get("scm_credential_id").(int) > 0 { 143 | credentials = strconv.Itoa(d.Get("scm_credential_id").(int)) 144 | } 145 | result, err := awxService.CreateProject(map[string]interface{}{ 146 | "name": projectName, 147 | "description": d.Get("description").(string), 148 | "local_path": d.Get("local_path").(string), 149 | "scm_type": d.Get("scm_type").(string), 150 | "scm_url": d.Get("scm_url").(string), 151 | "scm_branch": d.Get("scm_branch").(string), 152 | "scm_clean": d.Get("scm_clean").(bool), 153 | "scm_delete_on_update": d.Get("scm_delete_on_update").(bool), 154 | "organization": d.Get("organisation_id").(int), 155 | "credential": credentials, 156 | 157 | "scm_update_on_launch": d.Get("scm_update_on_launch").(bool), 158 | "scm_update_cache_timeout": d.Get("scm_update_cache_timeout").(int), 159 | }, map[string]string{}) 160 | if err != nil { 161 | return buildDiagnosticsMessage("Create: Project not created", "Project with name %s in the Organisation ID %v not created, %s", projectName, orgID, err.Error()) 162 | } 163 | 164 | d.SetId(strconv.Itoa(result.ID)) 165 | return resourceProjectRead(ctx, d, m) 166 | } 167 | 168 | func resourceProjectUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 169 | client := m.(*awx.AWX) 170 | awxService := client.ProjectService 171 | 172 | id, diags := convertStateIDToNummeric("Update Project", d) 173 | if diags.HasError() { 174 | return diags 175 | } 176 | credentials := "" 177 | if d.Get("scm_credential_id").(int) > 0 { 178 | credentials = strconv.Itoa(d.Get("scm_credential_id").(int)) 179 | } 180 | _, err := awxService.UpdateProject(id, map[string]interface{}{ 181 | "name": d.Get("name").(string), 182 | "description": d.Get("description").(string), 183 | "local_path": d.Get("local_path").(string), 184 | "scm_type": d.Get("scm_type").(string), 185 | "scm_url": d.Get("scm_url").(string), 186 | "scm_branch": d.Get("scm_branch").(string), 187 | "scm_clean": d.Get("scm_clean").(bool), 188 | "scm_delete_on_update": d.Get("scm_delete_on_update").(bool), 189 | "credential": credentials, 190 | "organization": d.Get("organisation_id").(int), 191 | "scm_update_on_launch": d.Get("scm_update_on_launch").(bool), 192 | "scm_update_cache_timeout": d.Get("scm_update_cache_timeout").(int), 193 | }, map[string]string{}) 194 | if err != nil { 195 | return buildDiagnosticsMessage("Update: Fail To Update Project", "Fail to get Project with ID %v, got %s", id, err.Error()) 196 | } 197 | return resourceProjectRead(ctx, d, m) 198 | } 199 | 200 | func resourceProjectRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 201 | var diags diag.Diagnostics 202 | client := m.(*awx.AWX) 203 | awxService := client.ProjectService 204 | 205 | id, diags := convertStateIDToNummeric("Read Project", d) 206 | if diags.HasError() { 207 | return diags 208 | } 209 | 210 | res, err := awxService.GetProjectById(id, make(map[string]string)) 211 | if err != nil { 212 | return buildDiagNotFoundFail("project", id, err) 213 | } 214 | d = setProjectResourceData(d, res) 215 | return diags 216 | } 217 | 218 | func resourceProjectDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 219 | var diags diag.Diagnostics 220 | digMessagePart := "Project" 221 | client := m.(*awx.AWX) 222 | awxService := client.ProjectService 223 | var jobID int 224 | var finished time.Time 225 | id, diags := convertStateIDToNummeric("Delete Project", d) 226 | if diags.HasError() { 227 | return diags 228 | } 229 | 230 | res, err := awxService.GetProjectById(id, make(map[string]string)) 231 | if err != nil { 232 | d.SetId("") 233 | return buildDiagNotFoundFail("project", id, err) 234 | } 235 | 236 | if res.SummaryFields.CurrentJob["id"] != nil { 237 | jobID = int(res.SummaryFields.CurrentJob["id"].(float64)) 238 | } else if res.SummaryFields.LastJob["id"] != nil { 239 | jobID = int(res.SummaryFields.LastJob["id"].(float64)) 240 | } 241 | if jobID != 0 { 242 | _, err = client.ProjectUpdatesService.ProjectUpdateCancel(jobID) 243 | if err != nil { 244 | return buildDiagnosticsMessage( 245 | "Delete: Fail to canel Job", 246 | "Fail to canel the Job %v for Project with ID %v, got %s", 247 | jobID, id, err.Error(), 248 | ) 249 | } 250 | } 251 | // check if finished is 0 252 | for finished.IsZero() { 253 | prj, _ := client.ProjectUpdatesService.ProjectUpdateGet(jobID) 254 | finished = prj.Finished 255 | time.Sleep(1 * time.Second) 256 | } 257 | 258 | if _, err = awxService.DeleteProject(id); err != nil { 259 | return buildDiagDeleteFail(digMessagePart, fmt.Sprintf("ProjectID %v, got %s ", id, err.Error())) 260 | } 261 | d.SetId("") 262 | return diags 263 | } 264 | 265 | func setProjectResourceData(d *schema.ResourceData, r *awx.Project) *schema.ResourceData { 266 | d.Set("name", r.Name) 267 | d.Set("description", r.Description) 268 | d.Set("scm_type", r.ScmType) 269 | d.Set("scm_url", r.ScmURL) 270 | d.Set("scm_branch", r.ScmBranch) 271 | d.Set("scm_clean", r.ScmClean) 272 | d.Set("scm_delete_on_update", r.ScmDeleteOnUpdate) 273 | d.Set("organisation_id", r.Organization) 274 | 275 | id, err := strconv.Atoi(r.Credential) 276 | if err == nil { 277 | d.Set("scm_credential_id", id) 278 | } 279 | d.Set("scm_update_on_launch", r.ScmUpdateOnLaunch) 280 | d.Set("scm_update_cache_timeout", r.ScmUpdateCacheTimeout) 281 | 282 | d.SetId(strconv.Itoa(r.ID)) 283 | return d 284 | } 285 | -------------------------------------------------------------------------------- /awx/resource_workflow_job_template_node.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | resource "random_uuid" "workflow_node_base_uuid" {} 8 | 9 | resource "awx_workflow_job_template_node" "default" { 10 | workflow_job_template_id = awx_workflow_job_template.default.id 11 | unified_job_template_id = awx_job_template.baseconfig.id 12 | inventory_id = awx_inventory.default.id 13 | identifier = random_uuid.workflow_node_base_uuid.result 14 | } 15 | ``` 16 | 17 | */ 18 | package awx 19 | 20 | import ( 21 | "context" 22 | "fmt" 23 | "log" 24 | "strconv" 25 | 26 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 27 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 28 | awx "github.com/mrcrilly/goawx/client" 29 | ) 30 | 31 | func resourceWorkflowJobTemplateNode() *schema.Resource { 32 | return &schema.Resource{ 33 | CreateContext: resourceWorkflowJobTemplateNodeCreate, 34 | ReadContext: resourceWorkflowJobTemplateNodeRead, 35 | UpdateContext: resourceWorkflowJobTemplateNodeUpdate, 36 | DeleteContext: resourceWorkflowJobTemplateNodeDelete, 37 | 38 | Schema: map[string]*schema.Schema{ 39 | 40 | "extra_data": &schema.Schema{ 41 | Type: schema.TypeString, 42 | Optional: true, 43 | Default: "", 44 | Description: "", 45 | StateFunc: normalizeJsonYaml, 46 | }, 47 | "inventory_id": &schema.Schema{ 48 | Type: schema.TypeInt, 49 | Optional: true, 50 | Description: "Inventory applied as a prompt, assuming job template prompts for inventory.", 51 | }, 52 | "scm_branch": &schema.Schema{ 53 | Type: schema.TypeString, 54 | Optional: true, 55 | Default: "", 56 | }, 57 | "job_type": &schema.Schema{ 58 | Type: schema.TypeString, 59 | Optional: true, 60 | Default: "run", 61 | }, 62 | "job_tags": &schema.Schema{ 63 | Type: schema.TypeString, 64 | Optional: true, 65 | }, 66 | "skip_tags": &schema.Schema{ 67 | Type: schema.TypeString, 68 | Optional: true, 69 | }, 70 | "limit": &schema.Schema{ 71 | Type: schema.TypeString, 72 | Optional: true, 73 | }, 74 | "diff_mode": &schema.Schema{ 75 | Type: schema.TypeBool, 76 | Optional: true, 77 | }, 78 | "verbosity": &schema.Schema{ 79 | Type: schema.TypeInt, 80 | Optional: true, 81 | Default: 0, 82 | }, 83 | "workflow_job_template_id": &schema.Schema{ 84 | Type: schema.TypeInt, 85 | Required: true, 86 | }, 87 | "unified_job_template_id": &schema.Schema{ 88 | Type: schema.TypeInt, 89 | Required: true, 90 | }, 91 | //"success_nodes": &schema.Schema{ 92 | // Type: schema.TypeList, 93 | // Elem: &schema.Schema{ 94 | // Type: schema.TypeInt, 95 | // }, 96 | // Optional: true, 97 | //}, 98 | //"failure_nodes": &schema.Schema{ 99 | // Type: schema.TypeList, 100 | // Elem: &schema.Schema{ 101 | // Type: schema.TypeInt, 102 | // }, 103 | // Optional: true, 104 | //}, 105 | //"always_nodes": &schema.Schema{ 106 | // Type: schema.TypeList, 107 | // Elem: &schema.Schema{ 108 | // Type: schema.TypeInt, 109 | // }, 110 | // Optional: true, 111 | //}, 112 | 113 | "all_parents_must_converge": &schema.Schema{ 114 | Type: schema.TypeBool, 115 | Optional: true, 116 | Default: true, 117 | }, 118 | "identifier": &schema.Schema{ 119 | Type: schema.TypeString, 120 | Required: true, 121 | }, 122 | }, 123 | //Importer: &schema.ResourceImporter{ 124 | // State: schema.ImportStatePassthrough, 125 | //}, 126 | // 127 | //Timeouts: &schema.ResourceTimeout{ 128 | // Create: schema.DefaultTimeout(1 * time.Minute), 129 | // Update: schema.DefaultTimeout(1 * time.Minute), 130 | // Delete: schema.DefaultTimeout(1 * time.Minute), 131 | //}, 132 | } 133 | } 134 | 135 | func resourceWorkflowJobTemplateNodeCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 136 | var diags diag.Diagnostics 137 | client := m.(*awx.AWX) 138 | awxService := client.WorkflowJobTemplateNodeService 139 | 140 | result, err := awxService.CreateWorkflowJobTemplateNode(map[string]interface{}{ 141 | "extra_data": d.Get("extra_data").(string), 142 | "inventory": d.Get("inventory_id").(int), 143 | "scm_branch": d.Get("scm_branch").(string), 144 | "skip_tags": d.Get("skip_tags").(string), 145 | "job_type": d.Get("job_type").(string), 146 | "job_tags": d.Get("job_tags").(string), 147 | "limit": d.Get("limit").(string), 148 | "diff_mode": d.Get("diff_mode").(bool), 149 | "verbosity": d.Get("verbosity").(int), 150 | "workflow_job_template": d.Get("workflow_job_template_id").(int), 151 | "unified_job_template": d.Get("unified_job_template_id").(int), 152 | //"failure_nodes": d.Get("failure_nodes").([]interface{}), 153 | //"success_nodes": d.Get("success_nodes").([]interface{}), 154 | //"always_nodes": d.Get("always_nodes").([]interface{}), 155 | 156 | "all_parents_must_converge": d.Get("all_parents_must_converge").(bool), 157 | "identifier": d.Get("identifier").(string), 158 | }, map[string]string{}) 159 | if err != nil { 160 | log.Printf("Fail to Create Template %v", err) 161 | diags = append(diags, diag.Diagnostic{ 162 | Severity: diag.Error, 163 | Summary: "Unable to create WorkflowJobTemplateNode", 164 | Detail: fmt.Sprintf("WorkflowJobTemplateNode with JobTemplateID %d and WorkflowID: %d faild to create %s", d.Get("unified_job_template_id").(int), d.Get("workflow_job_template_id").(int), err.Error()), 165 | }) 166 | return diags 167 | } 168 | 169 | d.SetId(strconv.Itoa(result.ID)) 170 | return resourceWorkflowJobTemplateNodeRead(ctx, d, m) 171 | } 172 | 173 | func resourceWorkflowJobTemplateNodeUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 174 | var diags diag.Diagnostics 175 | client := m.(*awx.AWX) 176 | awxService := client.WorkflowJobTemplateNodeService 177 | id, diags := convertStateIDToNummeric("Update WorkflowJobTemplateNode", d) 178 | if diags.HasError() { 179 | return diags 180 | } 181 | 182 | params := make(map[string]string) 183 | _, err := awxService.GetWorkflowJobTemplateNodeByID(id, params) 184 | if err != nil { 185 | return buildDiagNotFoundFail("workflow job template node", id, err) 186 | } 187 | 188 | _, err = awxService.UpdateWorkflowJobTemplateNode(id, map[string]interface{}{ 189 | "extra_data": d.Get("extra_data").(string), 190 | "inventory": d.Get("inventory_id").(int), 191 | "scm_branch": d.Get("scm_branch").(string), 192 | "skip_tags": d.Get("skip_tags").(string), 193 | "job_type": d.Get("job_type").(string), 194 | "job_tags": d.Get("job_tags").(string), 195 | "limit": d.Get("limit").(string), 196 | "diff_mode": d.Get("diff_mode").(bool), 197 | "verbosity": d.Get("verbosity").(int), 198 | "workflow_job_template": d.Get("workflow_job_template_id").(int), 199 | "unified_job_template": d.Get("unified_job_template_id").(int), 200 | //"failure_nodes": d.Get("failure_nodes").([]interface{}), 201 | //"success_nodes": d.Get("success_nodes").([]interface{}), 202 | //"always_nodes": d.Get("always_nodes").([]interface{}), 203 | "all_parents_must_converge": d.Get("all_parents_must_converge").(bool), 204 | "identifier": d.Get("identifier").(string), 205 | }, map[string]string{}) 206 | if err != nil { 207 | diags = append(diags, diag.Diagnostic{ 208 | Severity: diag.Error, 209 | Summary: "Unable to update WorkflowJobTemplateNode", 210 | Detail: fmt.Sprintf("WorkflowJobTemplateNode with name %s in the project id %d faild to update %s", d.Get("name").(string), d.Get("project_id").(int), err.Error()), 211 | }) 212 | return diags 213 | } 214 | 215 | return resourceWorkflowJobTemplateNodeRead(ctx, d, m) 216 | } 217 | 218 | func resourceWorkflowJobTemplateNodeRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 219 | var diags diag.Diagnostics 220 | client := m.(*awx.AWX) 221 | awxService := client.WorkflowJobTemplateNodeService 222 | id, diags := convertStateIDToNummeric("Read WorkflowJobTemplateNode", d) 223 | if diags.HasError() { 224 | return diags 225 | } 226 | 227 | res, err := awxService.GetWorkflowJobTemplateNodeByID(id, make(map[string]string)) 228 | if err != nil { 229 | return buildDiagNotFoundFail("workflow job template node", id, err) 230 | 231 | } 232 | d = setWorkflowJobTemplateNodeResourceData(d, res) 233 | return nil 234 | } 235 | 236 | func resourceWorkflowJobTemplateNodeDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 237 | client := m.(*awx.AWX) 238 | awxService := client.WorkflowJobTemplateNodeService 239 | id, diags := convertStateIDToNummeric(diagElementHostTitle, d) 240 | if diags.HasError() { 241 | return diags 242 | } 243 | 244 | if _, err := awxService.DeleteWorkflowJobTemplateNode(id); err != nil { 245 | return buildDiagDeleteFail( 246 | diagElementHostTitle, 247 | fmt.Sprintf("id %v, got %s ", 248 | id, err.Error())) 249 | } 250 | d.SetId("") 251 | return nil 252 | } 253 | 254 | func setWorkflowJobTemplateNodeResourceData(d *schema.ResourceData, r *awx.WorkflowJobTemplateNode) *schema.ResourceData { 255 | 256 | d.Set("extra_data", normalizeJsonYaml(r.ExtraData)) 257 | d.Set("inventory_id", strconv.Itoa(r.Inventory)) 258 | d.Set("scm_branch", r.ScmBranch) 259 | d.Set("job_type", r.JobType) 260 | d.Set("job_tags", r.JobTags) 261 | d.Set("skip_tags", r.SkipTags) 262 | d.Set("limit", r.Limit) 263 | d.Set("diff_mode", r.DiffMode) 264 | d.Set("verbosity", r.Verbosity) 265 | //d.Set("failure_nodes", r.FailureNodes) 266 | //d.Set("success_nodes", r.SuccessNodes) 267 | //d.Set("always_nodes", r.AlwaysNodes) 268 | 269 | d.Set("workflow_job_template_id", strconv.Itoa(r.WorkflowJobTemplate)) 270 | d.Set("unified_job_template_id", strconv.Itoa(r.UnifiedJobTemplate)) 271 | d.Set("all_parents_must_converge", r.AllParentsMustConverge) 272 | d.Set("identifier", r.Identifier) 273 | 274 | d.SetId(strconv.Itoa(r.ID)) 275 | return d 276 | } 277 | -------------------------------------------------------------------------------- /awx/resource_job_template.go: -------------------------------------------------------------------------------- 1 | /* 2 | *TBD* 3 | 4 | Example Usage 5 | 6 | ```hcl 7 | data "awx_inventory" "default" { 8 | name = "private_services" 9 | organisation_id = data.awx_organization.default.id 10 | } 11 | 12 | resource "awx_job_template" "baseconfig" { 13 | name = "baseconfig" 14 | job_type = "run" 15 | inventory_id = data.awx_inventory.default.id 16 | project_id = awx_project.base_service_config.id 17 | playbook = "master-configure-system.yml" 18 | become_enabled = true 19 | } 20 | ``` 21 | 22 | */ 23 | package awx 24 | 25 | import ( 26 | "context" 27 | "fmt" 28 | "log" 29 | "strconv" 30 | 31 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 32 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 33 | awx "github.com/mrcrilly/goawx/client" 34 | ) 35 | 36 | func resourceJobTemplate() *schema.Resource { 37 | return &schema.Resource{ 38 | CreateContext: resourceJobTemplateCreate, 39 | ReadContext: resourceJobTemplateRead, 40 | UpdateContext: resourceJobTemplateUpdate, 41 | DeleteContext: resourceJobTemplateDelete, 42 | 43 | Schema: map[string]*schema.Schema{ 44 | "name": &schema.Schema{ 45 | Type: schema.TypeString, 46 | Required: true, 47 | }, 48 | "description": &schema.Schema{ 49 | Type: schema.TypeString, 50 | Optional: true, 51 | Default: "", 52 | }, 53 | // Run, Check, Scan 54 | "job_type": &schema.Schema{ 55 | Type: schema.TypeString, 56 | Required: true, 57 | Description: "One of: run, check, scan", 58 | }, 59 | "inventory_id": &schema.Schema{ 60 | Type: schema.TypeString, 61 | Required: true, 62 | }, 63 | "project_id": &schema.Schema{ 64 | Type: schema.TypeInt, 65 | Required: true, 66 | }, 67 | "playbook": &schema.Schema{ 68 | Type: schema.TypeString, 69 | Optional: true, 70 | Default: "", 71 | }, 72 | "forks": &schema.Schema{ 73 | Type: schema.TypeInt, 74 | Optional: true, 75 | Default: 0, 76 | }, 77 | "limit": &schema.Schema{ 78 | Type: schema.TypeString, 79 | Optional: true, 80 | Default: "", 81 | }, 82 | //0,1,2,3,4,5 83 | "verbosity": &schema.Schema{ 84 | Type: schema.TypeInt, 85 | Optional: true, 86 | Default: 0, 87 | Description: "One of 0,1,2,3,4,5", 88 | }, 89 | "extra_vars": &schema.Schema{ 90 | Type: schema.TypeString, 91 | Optional: true, 92 | Default: "", 93 | }, 94 | "job_tags": &schema.Schema{ 95 | Type: schema.TypeString, 96 | Optional: true, 97 | Default: "", 98 | }, 99 | "force_handlers": &schema.Schema{ 100 | Type: schema.TypeBool, 101 | Optional: true, 102 | Default: false, 103 | }, 104 | "skip_tags": &schema.Schema{ 105 | Type: schema.TypeString, 106 | Optional: true, 107 | Default: "", 108 | }, 109 | "start_at_task": &schema.Schema{ 110 | Type: schema.TypeString, 111 | Optional: true, 112 | Default: "", 113 | }, 114 | "timeout": &schema.Schema{ 115 | Type: schema.TypeInt, 116 | Optional: true, 117 | Default: 0, 118 | }, 119 | "use_fact_cache": &schema.Schema{ 120 | Type: schema.TypeBool, 121 | Optional: true, 122 | Default: false, 123 | }, 124 | "host_config_key": &schema.Schema{ 125 | Type: schema.TypeString, 126 | Optional: true, 127 | Default: "", 128 | }, 129 | "ask_diff_mode_on_launch": &schema.Schema{ 130 | Type: schema.TypeBool, 131 | Optional: true, 132 | Default: false, 133 | }, 134 | "ask_limit_on_launch": &schema.Schema{ 135 | Type: schema.TypeBool, 136 | Optional: true, 137 | Default: false, 138 | }, 139 | "ask_tags_on_launch": &schema.Schema{ 140 | Type: schema.TypeBool, 141 | Optional: true, 142 | Default: false, 143 | }, 144 | "ask_verbosity_on_launch": &schema.Schema{ 145 | Type: schema.TypeBool, 146 | Optional: true, 147 | Default: false, 148 | }, 149 | "ask_inventory_on_launch": &schema.Schema{ 150 | Type: schema.TypeBool, 151 | Optional: true, 152 | Default: false, 153 | }, 154 | "ask_variables_on_launch": &schema.Schema{ 155 | Type: schema.TypeBool, 156 | Optional: true, 157 | Default: false, 158 | }, 159 | "ask_credential_on_launch": &schema.Schema{ 160 | Type: schema.TypeBool, 161 | Optional: true, 162 | Default: false, 163 | }, 164 | "survey_enabled": &schema.Schema{ 165 | Type: schema.TypeBool, 166 | Optional: true, 167 | Default: false, 168 | }, 169 | "become_enabled": &schema.Schema{ 170 | Type: schema.TypeBool, 171 | Optional: true, 172 | Default: false, 173 | }, 174 | "diff_mode": &schema.Schema{ 175 | Type: schema.TypeBool, 176 | Optional: true, 177 | Default: false, 178 | }, 179 | "ask_skip_tags_on_launch": &schema.Schema{ 180 | Type: schema.TypeBool, 181 | Optional: true, 182 | Default: false, 183 | }, 184 | "allow_simultaneous": &schema.Schema{ 185 | Type: schema.TypeBool, 186 | Optional: true, 187 | Default: false, 188 | }, 189 | "custom_virtualenv": &schema.Schema{ 190 | Type: schema.TypeString, 191 | Optional: true, 192 | Default: "", 193 | }, 194 | "ask_job_type_on_launch": &schema.Schema{ 195 | Type: schema.TypeBool, 196 | Optional: true, 197 | Default: false, 198 | }, 199 | }, 200 | //Importer: &schema.ResourceImporter{ 201 | // State: schema.ImportStatePassthrough, 202 | //}, 203 | // 204 | //Timeouts: &schema.ResourceTimeout{ 205 | // Create: schema.DefaultTimeout(1 * time.Minute), 206 | // Update: schema.DefaultTimeout(1 * time.Minute), 207 | // Delete: schema.DefaultTimeout(1 * time.Minute), 208 | //}, 209 | } 210 | } 211 | 212 | func resourceJobTemplateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 213 | var diags diag.Diagnostics 214 | client := m.(*awx.AWX) 215 | awxService := client.JobTemplateService 216 | 217 | result, err := awxService.CreateJobTemplate(map[string]interface{}{ 218 | "name": d.Get("name").(string), 219 | "description": d.Get("description").(string), 220 | "job_type": d.Get("job_type").(string), 221 | "inventory": AtoipOr(d.Get("inventory_id").(string), nil), 222 | "project": d.Get("project_id").(int), 223 | "playbook": d.Get("playbook").(string), 224 | "forks": d.Get("forks").(int), 225 | "limit": d.Get("limit").(string), 226 | "verbosity": d.Get("verbosity").(int), 227 | "extra_vars": d.Get("extra_vars").(string), 228 | "job_tags": d.Get("job_tags").(string), 229 | "force_handlers": d.Get("force_handlers").(bool), 230 | "skip_tags": d.Get("skip_tags").(string), 231 | "start_at_task": d.Get("start_at_task").(string), 232 | "timeout": d.Get("timeout").(int), 233 | "use_fact_cache": d.Get("use_fact_cache").(bool), 234 | "host_config_key": d.Get("host_config_key").(string), 235 | "ask_diff_mode_on_launch": d.Get("ask_diff_mode_on_launch").(bool), 236 | "ask_variables_on_launch": d.Get("ask_variables_on_launch").(bool), 237 | "ask_limit_on_launch": d.Get("ask_limit_on_launch").(bool), 238 | "ask_tags_on_launch": d.Get("ask_tags_on_launch").(bool), 239 | "ask_skip_tags_on_launch": d.Get("ask_skip_tags_on_launch").(bool), 240 | "ask_job_type_on_launch": d.Get("ask_job_type_on_launch").(bool), 241 | "ask_verbosity_on_launch": d.Get("ask_verbosity_on_launch").(bool), 242 | "ask_inventory_on_launch": d.Get("ask_inventory_on_launch").(bool), 243 | "ask_credential_on_launch": d.Get("ask_credential_on_launch").(bool), 244 | "survey_enabled": d.Get("survey_enabled").(bool), 245 | "become_enabled": d.Get("become_enabled").(bool), 246 | "diff_mode": d.Get("diff_mode").(bool), 247 | "allow_simultaneous": d.Get("allow_simultaneous").(bool), 248 | "custom_virtualenv": AtoipOr(d.Get("custom_virtualenv").(string), nil), 249 | }, map[string]string{}) 250 | if err != nil { 251 | log.Printf("Fail to Create Template %v", err) 252 | diags = append(diags, diag.Diagnostic{ 253 | Severity: diag.Error, 254 | Summary: "Unable to create JobTemplate", 255 | Detail: fmt.Sprintf("JobTemplate with name %s in the project id %d, faild to create %s", d.Get("name").(string), d.Get("project_id").(int), err.Error()), 256 | }) 257 | return diags 258 | } 259 | 260 | d.SetId(strconv.Itoa(result.ID)) 261 | return resourceJobTemplateRead(ctx, d, m) 262 | } 263 | 264 | func resourceJobTemplateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 265 | var diags diag.Diagnostics 266 | client := m.(*awx.AWX) 267 | awxService := client.JobTemplateService 268 | id, diags := convertStateIDToNummeric("Update JobTemplate", d) 269 | if diags.HasError() { 270 | return diags 271 | } 272 | 273 | params := make(map[string]string) 274 | _, err := awxService.GetJobTemplateByID(id, params) 275 | if err != nil { 276 | return buildDiagNotFoundFail("job template", id, err) 277 | } 278 | 279 | _, err = awxService.UpdateJobTemplate(id, map[string]interface{}{ 280 | "name": d.Get("name").(string), 281 | "description": d.Get("description").(string), 282 | "job_type": d.Get("job_type").(string), 283 | "inventory": AtoipOr(d.Get("inventory_id").(string), nil), 284 | "project": d.Get("project_id").(int), 285 | "playbook": d.Get("playbook").(string), 286 | "forks": d.Get("forks").(int), 287 | "limit": d.Get("limit").(string), 288 | "verbosity": d.Get("verbosity").(int), 289 | "extra_vars": d.Get("extra_vars").(string), 290 | "job_tags": d.Get("job_tags").(string), 291 | "force_handlers": d.Get("force_handlers").(bool), 292 | "skip_tags": d.Get("skip_tags").(string), 293 | "start_at_task": d.Get("start_at_task").(string), 294 | "timeout": d.Get("timeout").(int), 295 | "use_fact_cache": d.Get("use_fact_cache").(bool), 296 | "host_config_key": d.Get("host_config_key").(string), 297 | "ask_diff_mode_on_launch": d.Get("ask_diff_mode_on_launch").(bool), 298 | "ask_variables_on_launch": d.Get("ask_variables_on_launch").(bool), 299 | "ask_limit_on_launch": d.Get("ask_limit_on_launch").(bool), 300 | "ask_tags_on_launch": d.Get("ask_tags_on_launch").(bool), 301 | "ask_skip_tags_on_launch": d.Get("ask_skip_tags_on_launch").(bool), 302 | "ask_job_type_on_launch": d.Get("ask_job_type_on_launch").(bool), 303 | "ask_verbosity_on_launch": d.Get("ask_verbosity_on_launch").(bool), 304 | "ask_inventory_on_launch": d.Get("ask_inventory_on_launch").(bool), 305 | "ask_credential_on_launch": d.Get("ask_credential_on_launch").(bool), 306 | "survey_enabled": d.Get("survey_enabled").(bool), 307 | "become_enabled": d.Get("become_enabled").(bool), 308 | "diff_mode": d.Get("diff_mode").(bool), 309 | "allow_simultaneous": d.Get("allow_simultaneous").(bool), 310 | "custom_virtualenv": AtoipOr(d.Get("custom_virtualenv").(string), nil), 311 | }, map[string]string{}) 312 | if err != nil { 313 | diags = append(diags, diag.Diagnostic{ 314 | Severity: diag.Error, 315 | Summary: "Unable to update JobTemplate", 316 | Detail: fmt.Sprintf("JobTemplate with name %s in the project id %d faild to update %s", d.Get("name").(string), d.Get("project_id").(int), err.Error()), 317 | }) 318 | return diags 319 | } 320 | 321 | return resourceJobTemplateRead(ctx, d, m) 322 | } 323 | 324 | func resourceJobTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 325 | var diags diag.Diagnostics 326 | client := m.(*awx.AWX) 327 | awxService := client.JobTemplateService 328 | id, diags := convertStateIDToNummeric("Read JobTemplate", d) 329 | if diags.HasError() { 330 | return diags 331 | } 332 | 333 | res, err := awxService.GetJobTemplateByID(id, make(map[string]string)) 334 | if err != nil { 335 | return buildDiagNotFoundFail("job template", id, err) 336 | 337 | } 338 | d = setJobTemplateResourceData(d, res) 339 | return nil 340 | } 341 | 342 | func setJobTemplateResourceData(d *schema.ResourceData, r *awx.JobTemplate) *schema.ResourceData { 343 | d.Set("allow_simultaneous", r.AllowSimultaneous) 344 | d.Set("ask_credential_on_launch", r.AskCredentialOnLaunch) 345 | d.Set("ask_job_type_on_launch", r.AskJobTypeOnLaunch) 346 | d.Set("ask_limit_on_launch", r.AskLimitOnLaunch) 347 | d.Set("ask_skip_tags_on_launch", r.AskSkipTagsOnLaunch) 348 | d.Set("ask_tags_on_launch", r.AskTagsOnLaunch) 349 | d.Set("ask_variables_on_launch", r.AskVariablesOnLaunch) 350 | d.Set("description", r.Description) 351 | d.Set("extra_vars", r.ExtraVars) 352 | d.Set("force_handlers", r.ForceHandlers) 353 | d.Set("forks", r.Forks) 354 | d.Set("host_config_key", r.HostConfigKey) 355 | d.Set("inventory_id", r.Inventory) 356 | d.Set("job_tags", r.JobTags) 357 | d.Set("job_type", r.JobType) 358 | d.Set("diff_mode", r.DiffMode) 359 | d.Set("custom_virtualenv", r.CustomVirtualenv) 360 | d.Set("limit", r.Limit) 361 | d.Set("name", r.Name) 362 | d.Set("become_enabled", r.BecomeEnabled) 363 | d.Set("use_fact_cache", r.UseFactCache) 364 | d.Set("playbook", r.Playbook) 365 | d.Set("project_id", r.Project) 366 | d.Set("skip_tags", r.SkipTags) 367 | d.Set("start_at_task", r.StartAtTask) 368 | d.Set("survey_enabled", r.SurveyEnabled) 369 | d.Set("verbosity", r.Verbosity) 370 | d.SetId(strconv.Itoa(r.ID)) 371 | return d 372 | } 373 | --------------------------------------------------------------------------------