From d4fb4d8307c24ba2ba2dc2b65c47266dd83e1841 Mon Sep 17 00:00:00 2001 From: Anselm Eberhardt Date: Thu, 7 Nov 2024 15:00:20 +0100 Subject: [PATCH 1/2] Add vault credential resource --- docs/resources/credential_vault.md | 44 +++++ .../awx_credential_vault/resource.tf | 10 + internal/awx/provider.go | 1 + internal/awx/resource_credential_vault.go | 179 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 docs/resources/credential_vault.md create mode 100644 examples/resources/awx_credential_vault/resource.tf create mode 100644 internal/awx/resource_credential_vault.go diff --git a/docs/resources/credential_vault.md b/docs/resources/credential_vault.md new file mode 100644 index 00000000..bf12d971 --- /dev/null +++ b/docs/resources/credential_vault.md @@ -0,0 +1,44 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "awx_credential_vault Resource - terraform-provider-awx" +subcategory: "" +description: |- + awx_credential_vault manages vault credentials in AWX. +--- + +# awx_credential_vault (Resource) + +`awx_credential_vault` manages vault credentials in AWX. + +## Example Usage + +```terraform +resource "awx_organization" "example" { + name = "example" +} + +resource "awx_credential_vault" "example" { + name = "vault-credential" + organization_id = awx_organization.example.id + description = "This is a vault credential" + vault_password = "password" +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the credential. +- `vault_password` (String, Sensitive) Vault Password. + +### Optional + +- `description` (String) The description of the credential. +- `organization_id` (Number) The organization ID this credential belongs to. +- `vault_id` (String) The vault identity to use. + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/examples/resources/awx_credential_vault/resource.tf b/examples/resources/awx_credential_vault/resource.tf new file mode 100644 index 00000000..50407d0c --- /dev/null +++ b/examples/resources/awx_credential_vault/resource.tf @@ -0,0 +1,10 @@ +resource "awx_organization" "example" { + name = "example" +} + +resource "awx_credential_vault" "example" { + name = "vault-credential" + organization_id = awx_organization.example.id + description = "This is a vault credential" + vault_password = "password" +} diff --git a/internal/awx/provider.go b/internal/awx/provider.go index 9c8d4a7a..389d59e1 100644 --- a/internal/awx/provider.go +++ b/internal/awx/provider.go @@ -63,6 +63,7 @@ func Provider() *schema.Provider { //nolint:funlen "awx_credential_scm": resourceCredentialSCM(), "awx_credential_gitlab": resourceCredentialGitlab(), "awx_credential_galaxy": resourceCredentialGalaxy(), + "awx_credential_vault": resourceCredentialVault(), "awx_execution_environment": resourceExecutionEnvironment(), "awx_host": resourceHost(), "awx_instance_group": resourceInstanceGroup(), diff --git a/internal/awx/resource_credential_vault.go b/internal/awx/resource_credential_vault.go new file mode 100644 index 00000000..5eafcbe6 --- /dev/null +++ b/internal/awx/resource_credential_vault.go @@ -0,0 +1,179 @@ +package awx + +import ( + "context" + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + awx "github.com/josh-silvas/terraform-provider-awx/tools/goawx" +) + +const vaultCredentialTypeName = "Vault" //nolint:gosec + +func resourceCredentialVault() *schema.Resource { + return &schema.Resource{ + Description: "`awx_credential_vault` manages vault credentials in AWX.", + CreateContext: resourceCredentialVaultCreate, + ReadContext: resourceCredentialVaultRead, + UpdateContext: resourceCredentialVaultUpdate, + DeleteContext: resourceCredentialDelete, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the credential.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the credential.", + }, + "organization_id": { + Type: schema.TypeInt, + Optional: true, + Description: "The organization ID this credential belongs to.", + }, + "vault_password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "Vault Password.", + }, + "vault_id": { + Type: schema.TypeString, + Optional: true, + Description: "The vault identity to use.", + }, + }, + } +} + +func resourceCredentialVaultCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + var err error + + client := m.(*awx.AWX) + vaultCredType, err := client.CredentialTypeService.GetCredentialTypeByName(vaultCredentialTypeName, map[string]string{}) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to create new credentials", + Detail: fmt.Sprintf("Unable to fetch credential type with Name: %s. Error: %s", vaultCredentialTypeName, err.Error()), + }) + return diags + } + + newCredential := map[string]interface{}{ + "name": d.Get("name").(string), + "description": d.Get("description").(string), + "organization": d.Get("organization_id").(int), + "credential_type": vaultCredType.ID, + "inputs": map[string]interface{}{ + "vault_password": d.Get("vault_password").(string), + "vault_id": d.Get("vault_id").(string), + }, + } + + cred, err := client.CredentialsService.CreateCredentials(newCredential, map[string]string{}) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to create new credentials", + Detail: fmt.Sprintf("Unable to create new credentials: %s", err.Error()), + }) + return diags + } + + d.SetId(strconv.Itoa(cred.ID)) + resourceCredentialVaultRead(ctx, d, m) + + return diags +} + +func resourceCredentialVaultRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + client := m.(*awx.AWX) + id, _ := strconv.Atoi(d.Id()) + cred, err := client.CredentialsService.GetCredentialsByID(id, map[string]string{}) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to fetch credentials", + Detail: fmt.Sprintf("Unable to fetch credentials with id %d: %s", id, err.Error()), + }) + return diags + } + + if err := d.Set("name", cred.Name); err != nil { + return diag.FromErr(err) + } + if err := d.Set("description", cred.Description); err != nil { + return diag.FromErr(err) + } + if err := d.Set("organization_id", cred.OrganizationID); err != nil { + return diag.FromErr(err) + } + if err := d.Set("vault_password", cred.Inputs["vault_password"]); err != nil { + return diag.FromErr(err) + } + if err := d.Set("vault_id", cred.Inputs["vault_id"]); err != nil { + return diag.FromErr(err) + } + + return diags +} + +func resourceCredentialVaultUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + keys := []string{ + "name", + "description", + "organization_id", + "vault_password", + "vault_id", + } + + client := m.(*awx.AWX) + + if d.HasChanges(keys...) { + var err error + + vaultCredType, err := client.CredentialTypeService.GetCredentialTypeByName(vaultCredentialTypeName, map[string]string{}) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to create new credentials", + Detail: fmt.Sprintf("Unable to fetch credential type with Name: %s. Error: %s", vaultCredentialTypeName, err.Error()), + }) + return diags + } + + id, _ := strconv.Atoi(d.Id()) + updatedCredential := map[string]interface{}{ + "name": d.Get("name").(string), + "description": d.Get("description").(string), + "organization": d.Get("organization_id").(int), + "credential_type": vaultCredType.ID, + "inputs": map[string]interface{}{ + "vault_password": d.Get("vault_password").(string), + "vault_id": d.Get("vault_id").(string), + }, + } + + _, err = client.CredentialsService.UpdateCredentialsByID(id, updatedCredential, map[string]string{}) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to update existing credentials", + Detail: fmt.Sprintf("Unable to update existing credentials with id %d: %s", id, err.Error()), + }) + return diags + } + } + + return resourceCredentialVaultRead(ctx, d, m) +} From 3756922b81143ddab5a16ef512801e0ffe8d73d3 Mon Sep 17 00:00:00 2001 From: Anselm Eberhardt Date: Thu, 7 Nov 2024 17:07:43 +0100 Subject: [PATCH 2/2] Bump version to v1.2.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index eede00b7..79127d85 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.1.7 +v1.2.0