Skip to content

Commit

Permalink
VAULT-32136: Enable updates to Vault Radar integration subscriptions. (
Browse files Browse the repository at this point in the history
…hashicorp#1139)

* VAULT-32136: Enable updates to Vault Radar integration subscriptions.

* Add change log.
  • Loading branch information
trentdibacco authored Nov 14, 2024
1 parent 388d206 commit 2f5ce38
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .changelog/1139.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
Enable updates to Vault Radar integration subscriptions.
```
13 changes: 13 additions & 0 deletions internal/clients/vault_radar.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,16 @@ func DeleteIntegrationSubscription(ctx context.Context, client *Client, projectI

return nil
}

func UpdateIntegrationSubscription(ctx context.Context, client *Client, projectID string, subscription iss.UpdateIntegrationSubscriptionBody) error {
params := iss.NewUpdateIntegrationSubscriptionParams()
params.Context = ctx
params.LocationProjectID = projectID
params.Body = subscription

if _, err := client.RadarSubscriptionService.UpdateIntegrationSubscription(params, nil); err != nil {
return err
}

return nil
}
60 changes: 57 additions & 3 deletions internal/provider/vaultradar/integration_subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,61 @@ func (r *integrationSubscriptionResource) Delete(ctx context.Context, req resour
}

func (r *integrationSubscriptionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// In-place update is not supported.
// Plans to support updating subscription details will be in a future iteration.
resp.Diagnostics.AddError("Unexpected provider error", "This is an internal error, please report this issue to the provider developers")
plan, planDiags := r.GetSubscriptionFromPlan(ctx, req.Plan)
resp.Diagnostics.Append(planDiags...)

state, stateDiags := r.GetSubscriptionFromState(ctx, req.State)
resp.Diagnostics.Append(stateDiags...)

if resp.Diagnostics.HasError() {
return
}

projectID := r.client.Config.ProjectID
if !plan.GetProjectID().IsUnknown() {
projectID = plan.GetProjectID().ValueString()
}

// Initialize the update body with the subscription ID.
update := service.UpdateIntegrationSubscriptionBody{
ID: plan.GetID().ValueString(),
}

// Check if the name was updated
if !plan.GetName().Equal(state.GetName()) {
tflog.Trace(ctx, "Radar integration subscription name changed.")
update.Name = plan.GetName().ValueString()
}

// Check if the connection id was updated
if !plan.GetConnectionID().Equal(state.GetConnectionID()) {
tflog.Trace(ctx, "Radar integration subscription connection id changed.")
update.ConnectionID = plan.GetConnectionID().ValueString()
}

planDetails, planDiags := plan.GetDetails()
resp.Diagnostics.Append(planDiags...)

stateDetails, stateDiags := state.GetDetails()
resp.Diagnostics.Append(stateDiags...)

if resp.Diagnostics.HasError() {
return
}

// Check if the details were updated
if planDetails != stateDetails {
tflog.Trace(ctx, "Radar integration subscription details changed.")
update.Details = planDetails
}

if err := clients.UpdateIntegrationSubscription(ctx, r.client, projectID, update); err != nil {
resp.Diagnostics.AddError("Error Updating Radar subscription", err.Error())
return
}

tflog.Info(ctx, "Radar integration subscription updated.")

// Store the updated plan values
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest"
)

Expand Down Expand Up @@ -74,6 +75,11 @@ func TestRadarIntegrationJiraConnection(t *testing.T) {
token = %q
}
`, projectID, updatedName, baseURL, email, token),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.example", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_connection.example", "name", updatedName),
),
Expand All @@ -89,6 +95,11 @@ func TestRadarIntegrationJiraConnection(t *testing.T) {
token = %q
}
`, projectID, updatedName, updatedBaseURL, email, token),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.example", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_connection.example", "base_url", updatedBaseURL),
),
Expand All @@ -104,6 +115,11 @@ func TestRadarIntegrationJiraConnection(t *testing.T) {
token = %q
}
`, projectID, updatedName, updatedBaseURL, updateEmail, token),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.example", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_connection.example", "email", updateEmail),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@ var integrationJiraSubscriptionSchema = schema.Schema{
"id": schema.StringAttribute{
Computed: true,
Description: "The ID of this resource.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"name": schema.StringAttribute{
Description: "Name of subscription. Name must be unique.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
Expand All @@ -56,14 +59,14 @@ var integrationJiraSubscriptionSchema = schema.Schema{
Description: "id of the integration jira connection to use for the subscription.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
},
"jira_project_key": schema.StringAttribute{
Description: "The name of the project under which the jira issue will be created. Example: OPS",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
Expand All @@ -73,7 +76,7 @@ var integrationJiraSubscriptionSchema = schema.Schema{
Description: "The type of issue to be created from the event(s). Example: Task",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
Expand All @@ -85,7 +88,7 @@ var integrationJiraSubscriptionSchema = schema.Schema{
Description: "The identifier of the Jira user who will be assigned the ticket. In case of Jira Cloud, this will be the Atlassian Account ID of the user. Example: 71509:11bb945b-c0de-4bac-9d57-9f09db2f7bc9",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
Expand All @@ -95,7 +98,7 @@ var integrationJiraSubscriptionSchema = schema.Schema{
Description: "This message will be included in the ticket description.",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.UseStateForUnknown(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest"
)

Expand Down Expand Up @@ -36,6 +37,9 @@ func TestRadarIntegrationJiraSubscription(t *testing.T) {
}

message := "AC test message"
updatedMessage := "AC test message updated"
name := "AC Test of Jira Subscription From TF"
updatedName := "AC Test of Updating Jira Subscription From TF"

resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
Expand All @@ -55,7 +59,7 @@ func TestRadarIntegrationJiraSubscription(t *testing.T) {
resource "hcp_vault_radar_integration_jira_subscription" "jira_subscription" {
project_id = hcp_vault_radar_integration_jira_connection.jira_connection.project_id
name = "AC Test of Jira Subscription From TF"
name = %q
connection_id = hcp_vault_radar_integration_jira_connection.jira_connection.id
jira_project_key = %q
issue_type = %q
Expand All @@ -64,16 +68,129 @@ func TestRadarIntegrationJiraSubscription(t *testing.T) {
}
`, projectID, baseURL, email, token,
jiraProjectKey, issueType, assignee, message),
name, jiraProjectKey, issueType, assignee, message),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("hcp_vault_radar_integration_jira_subscription.jira_subscription", "connection_id"),
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "name", name),
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "jira_project_key", jiraProjectKey),
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "issue_type", issueType),
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "assignee", assignee),
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "message", message),
),
},
// UPDATE not supported at this time.
// Update Name
{
Config: fmt.Sprintf(`
# An integration_jira_subscription is required to create a hcp_vault_radar_integration_jira_subscription.
resource "hcp_vault_radar_integration_jira_connection" "jira_connection" {
project_id = %q
name = "AC Test of Jira Connect from TF"
base_url = %q
email = %q
token = %q
}
resource "hcp_vault_radar_integration_jira_subscription" "jira_subscription" {
project_id = hcp_vault_radar_integration_jira_connection.jira_connection.project_id
name = %q
connection_id = hcp_vault_radar_integration_jira_connection.jira_connection.id
jira_project_key = %q
issue_type = %q
assignee = %q
message = %q
}
`, projectID, baseURL, email, token,
updatedName, jiraProjectKey, issueType, assignee, message),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.jira_connection", plancheck.ResourceActionNoop),
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_subscription.jira_subscription", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "name", updatedName),
),
},
// Update Message. This effectively cause an update in the details of the connection.
{
Config: fmt.Sprintf(`
# An integration_jira_subscription is required to create a hcp_vault_radar_integration_jira_subscription.
resource "hcp_vault_radar_integration_jira_connection" "jira_connection" {
project_id = %q
name = "AC Test of Jira Connect from TF"
base_url = %q
email = %q
token = %q
}
resource "hcp_vault_radar_integration_jira_subscription" "jira_subscription" {
project_id = hcp_vault_radar_integration_jira_connection.jira_connection.project_id
name = %q
connection_id = hcp_vault_radar_integration_jira_connection.jira_connection.id
jira_project_key = %q
issue_type = %q
assignee = %q
message = %q
}
`, projectID, baseURL, email, token,
updatedName, jiraProjectKey, issueType, assignee, updatedMessage),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.jira_connection", plancheck.ResourceActionNoop),
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_subscription.jira_subscription", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_jira_subscription.jira_subscription", "message", updatedMessage),
),
},
// UPDATE Connection ID.
{
Config: fmt.Sprintf(`
# An integration_jira_subscription is required to create a hcp_vault_radar_integration_jira_subscription.
resource "hcp_vault_radar_integration_jira_connection" "jira_connection" {
project_id = %q
name = "AC Test of Jira Connect from TF"
base_url = %q
email = %q
token = %q
}
# Create another integration_jira_subscription to connect to.
resource "hcp_vault_radar_integration_jira_connection" "jira_connection_2" {
project_id = %q
name = "AC Test of Jira Connect from TF 2"
base_url = %q
email = %q
token = %q
}
resource "hcp_vault_radar_integration_jira_subscription" "jira_subscription" {
project_id = hcp_vault_radar_integration_jira_connection.jira_connection.project_id
name = %q
connection_id = hcp_vault_radar_integration_jira_connection.jira_connection_2.id
jira_project_key = %q
issue_type = %q
assignee = %q
message = %q
}
`, projectID, baseURL, email, token, // For the first connection.
projectID, baseURL, email, token, // For the second connection.
updatedName, jiraProjectKey, issueType, assignee, updatedMessage),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.jira_connection", plancheck.ResourceActionNoop),
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_connection.jira_connection_2", plancheck.ResourceActionCreate),
plancheck.ExpectResourceAction("hcp_vault_radar_integration_jira_subscription.jira_subscription", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("hcp_vault_radar_integration_jira_subscription.jira_subscription", "connection_id"),
),
},
// DELETE happens automatically.
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest"
)

Expand Down Expand Up @@ -56,6 +57,11 @@ func TestRadarIntegrationSlackConnection(t *testing.T) {
token = %q
}
`, projectID, updatedName, token),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_slack_connection.example", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("hcp_vault_radar_integration_slack_connection.example", "name", updatedName),
),
Expand All @@ -69,6 +75,11 @@ func TestRadarIntegrationSlackConnection(t *testing.T) {
token = %q
}
`, projectID, updatedName, updateToken),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("hcp_vault_radar_integration_slack_connection.example", plancheck.ResourceActionUpdate),
},
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrWith("hcp_vault_radar_integration_slack_connection.example", "token", func(value string) error {
if value != updateToken {
Expand Down
Loading

0 comments on commit 2f5ce38

Please sign in to comment.