Onboard Argus ACL (#304)

* resource create and schema/model

* consider empty value in resource creation

* Address issue in mapfields that came up in testing

* Unit testing the mapFields func

* extend update

* extend read

* extend datasource.go

* update example

* extended acceptance tests and generated docs

* update description and comments

* improve messages and var names, fix update acceptance test

* extend acceptance tests, improve error messages
This commit is contained in:
Diogo Ferrão 2024-03-22 17:35:10 +00:00 committed by GitHub
parent 8eb14a1136
commit c2389be47b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 379 additions and 22 deletions

View file

@ -29,6 +29,7 @@ data "stackit_argus_instance" "example" {
### Read-Only
- `acl` (Set of String) The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation.
- `alerting_url` (String) Specifies Alerting URL.
- `dashboard_url` (String) Specifies Argus instance dashboard URL.
- `grafana_initial_admin_password` (String, Sensitive) Specifies an initial Grafana admin password.

View file

@ -17,6 +17,7 @@ resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
}
```
@ -31,6 +32,7 @@ resource "stackit_argus_instance" "example" {
### Optional
- `acl` (Set of String) The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation.
- `parameters` (Map of String) Additional parameters.
### Read-Only

View file

@ -2,4 +2,5 @@ resource "stackit_argus_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Monitoring-Medium-EU01"
acl = ["1.1.1.1/32", "2.2.2.2/32"]
}

View file

@ -22,6 +22,9 @@ var instanceResource = map[string]string{
"name": testutil.ResourceNameWithDateTime("argus"),
"plan_name": "Monitoring-Basic-EU01",
"new_plan_name": "Monitoring-Medium-EU01",
"acl-0": "1.2.3.4/32",
"acl-1": "111.222.111.222/32",
"acl-1-updated": "111.222.111.125/32",
}
var scrapeConfigResource = map[string]string{
@ -39,8 +42,9 @@ var credentialResource = map[string]string{
"project_id": testutil.ProjectId,
}
func resourceConfig(instanceName, planName, target, saml2EnableUrlParameters string) string {
return fmt.Sprintf(`
func resourceConfig(acl *string, instanceName, planName, target, saml2EnableUrlParameters string) string {
if acl == nil {
return fmt.Sprintf(`
%s
resource "stackit_argus_instance" "instance" {
@ -68,10 +72,52 @@ func resourceConfig(instanceName, planName, target, saml2EnableUrlParameters str
}
`,
testutil.ArgusProviderConfig(),
instanceResource["project_id"],
instanceName,
planName,
scrapeConfigResource["name"],
scrapeConfigResource["metrics_path"],
target,
scrapeConfigResource["scrape_interval"],
scrapeConfigResource["sample_limit"],
saml2EnableUrlParameters,
)
}
return fmt.Sprintf(`
%s
resource "stackit_argus_instance" "instance" {
project_id = "%s"
name = "%s"
plan_name = "%s"
acl = %s
}
resource "stackit_argus_scrapeconfig" "scrapeconfig" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
name = "%s"
metrics_path = "%s"
targets = [%s]
scrape_interval = "%s"
sample_limit = %s
saml2 = {
enable_url_parameters = %s
}
}
resource "stackit_argus_credential" "credential" {
project_id = stackit_argus_instance.instance.project_id
instance_id = stackit_argus_instance.instance.instance_id
}
`,
testutil.ArgusProviderConfig(),
instanceResource["project_id"],
instanceName,
planName,
*acl,
scrapeConfigResource["name"],
scrapeConfigResource["metrics_path"],
target,
@ -88,7 +134,18 @@ func TestAccResource(t *testing.T) {
Steps: []resource.TestStep{
// Creation
{
Config: resourceConfig(instanceResource["name"], instanceResource["plan_name"], scrapeConfigResource["urls"], scrapeConfigResource["saml2_enable_url_parameters"]),
Config: resourceConfig(
utils.Ptr(fmt.Sprintf(
"[%q, %q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1"],
instanceResource["acl-1"],
)),
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
@ -115,6 +172,11 @@ func TestAccResource(t *testing.T) {
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.1", instanceResource["acl-1"]),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
@ -141,7 +203,73 @@ func TestAccResource(t *testing.T) {
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
}, {
},
// Creation without ACL
{
Config: resourceConfig(
nil,
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "dashboard_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "is_updatable"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_public_read_access"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_user"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "grafana_initial_admin_password"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days_5m_downsampling"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_retention_days_1h_downsampling"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "metrics_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "targets_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "alerting_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "logs_push_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "jaeger_ui_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "otlp_traces_url"),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "zipkin_spans_url"),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "0"),
// scrape config data
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"stackit_argus_scrapeconfig.scrapeconfig", "project_id",
),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_scrapeconfig.scrapeconfig", "instance_id",
),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.0.urls.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "metrics_path", scrapeConfigResource["metrics_path"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", scrapeConfigResource["saml2_enable_url_parameters"]),
// credentials
resource.TestCheckResourceAttr("stackit_argus_credential.credential", "project_id", credentialResource["project_id"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "instance_id",
"stackit_argus_credential.credential", "instance_id",
),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "username"),
resource.TestCheckResourceAttrSet("stackit_argus_credential.credential", "password"),
),
},
{
// Data source
Config: fmt.Sprintf(`
%s
@ -157,7 +285,16 @@ func TestAccResource(t *testing.T) {
name = stackit_argus_scrapeconfig.scrapeconfig.name
}
`,
resourceConfig(instanceResource["name"], instanceResource["plan_name"], scrapeConfigResource["urls"], scrapeConfigResource["saml2_enable_url_parameters"]),
resourceConfig(utils.Ptr(fmt.Sprintf(
"[%q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1"],
)),
instanceResource["name"],
instanceResource["plan_name"],
scrapeConfigResource["urls"],
scrapeConfigResource["saml2_enable_url_parameters"],
),
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
@ -165,6 +302,9 @@ func TestAccResource(t *testing.T) {
resource.TestCheckResourceAttrSet("data.stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "plan_name", instanceResource["plan_name"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("data.stackit_argus_instance.instance", "acl.1", instanceResource["acl-1"]),
resource.TestCheckResourceAttrPair(
"stackit_argus_instance.instance", "project_id",
"data.stackit_argus_instance.instance", "project_id",
@ -236,13 +376,25 @@ func TestAccResource(t *testing.T) {
},
// Update
{
Config: resourceConfig(fmt.Sprintf("%s-new", instanceResource["name"]), instanceResource["new_plan_name"], "", "true"),
Config: resourceConfig(utils.Ptr(fmt.Sprintf(
"[%q, %q]",
instanceResource["acl-0"],
instanceResource["acl-1-updated"],
)),
fmt.Sprintf("%s-new", instanceResource["name"]),
instanceResource["new_plan_name"],
"",
"true",
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "project_id", instanceResource["project_id"]),
resource.TestCheckResourceAttrSet("stackit_argus_instance.instance", "instance_id"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]+"-new"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["new_plan_name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "2"),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.0", instanceResource["acl-0"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.1", instanceResource["acl-1-updated"]),
// Scrape Config
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
@ -300,6 +452,9 @@ func TestAccResource(t *testing.T) {
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "name", instanceResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "plan_name", instanceResource["new_plan_name"]),
// ACL
resource.TestCheckResourceAttr("stackit_argus_instance.instance", "acl.#", "0"),
// Scrape Config
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "name", scrapeConfigResource["name"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "targets.#", "1"),
@ -307,8 +462,8 @@ func TestAccResource(t *testing.T) {
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scheme", scrapeConfigResource["scheme"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "scrape_interval", scrapeConfigResource["scrape_interval"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "sample_limit", scrapeConfigResource["sample_limit"]),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.%", "0"),
resource.TestCheckNoResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.%", "1"),
resource.TestCheckResourceAttr("stackit_argus_scrapeconfig.scrapeconfig", "saml2.enable_url_parameters", "false"),
),
},

View file

@ -196,6 +196,11 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
"zipkin_spans_url": schema.StringAttribute{
Computed: true,
},
"acl": schema.SetAttribute{
Description: "The access control list for this instance. Each entry is a single IP address that is permitted to access, in CIDR notation (/32).",
ElementType: types.StringType,
Computed: true,
},
},
}
}
@ -216,7 +221,13 @@ func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
return
}
err = mapFields(ctx, instanceResponse, &model)
aclList, err := d.client.ListACL(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API to list ACL data: %v", err))
return
}
err = mapFields(ctx, instanceResponse, aclList, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
return

View file

@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
@ -17,6 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/argus"
"github.com/stackitcloud/stackit-sdk-go/services/argus/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
@ -58,6 +60,7 @@ type Model struct {
JaegerUIURL types.String `tfsdk:"jaeger_ui_url"`
OtlpTracesURL types.String `tfsdk:"otlp_traces_url"`
ZipkinSpansURL types.String `tfsdk:"zipkin_spans_url"`
ACL types.Set `tfsdk:"acl"`
}
// NewInstanceResource is a helper function to simplify the provider implementation.
@ -250,6 +253,16 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
"zipkin_spans_url": schema.StringAttribute{
Computed: true,
},
"acl": schema.SetAttribute{
Description: "The access control list for this instance. Each entry is a single IP address that is permitted to access, in CIDR notation (/32).",
ElementType: types.StringType,
Optional: true,
Validators: []validator.Set{
setvalidator.ValueStringsAre(
validate.CIDR(),
),
},
},
},
}
}
@ -264,6 +277,15 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
return
}
acl := []string{}
if !(model.ACL.IsNull() || model.ACL.IsUnknown()) {
diags = model.ACL.ElementsAs(ctx, &acl, false)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
projectId := model.ProjectId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
@ -273,12 +295,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
return
}
// Generate API request body from model
payload, err := toCreatePayload(&model)
createPayload, err := toCreatePayload(&model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating API payload: %v", err))
return
}
createResp, err := r.client.CreateInstance(ctx, projectId).CreateInstancePayload(*payload).Execute()
createResp, err := r.client.CreateInstance(ctx, projectId).CreateInstancePayload(*createPayload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err))
return
@ -292,11 +314,38 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
}
// Map response body to schema
err = mapFields(ctx, waitResp, &model)
err = mapFields(ctx, waitResp, nil, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
// Set state to instance populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// Create ACL
err = updateACL(ctx, projectId, *instanceId, acl, r.client)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating ACL: %v", err))
return
}
aclList, err := r.client.ListACL(ctx, *instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API to list ACL data: %v", err))
return
}
// Map response body to schema
err = mapFields(ctx, waitResp, aclList, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API response: %v", err))
return
}
// Set state to fully populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
@ -325,19 +374,27 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}
aclList, err := r.client.ListACL(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API for ACL data: %v", err))
return
}
// Map response body to schema
err = mapFields(ctx, instanceResp, &model)
err = mapFields(ctx, instanceResp, aclList, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
// Set refreshed model
// Set state to fully populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus instance created")
tflog.Info(ctx, "Argus instance read")
}
// Update updates the resource and sets the updated Terraform state on success.
@ -352,6 +409,15 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
acl := []string{}
if !(model.ACL.IsNull() || model.ACL.IsUnknown()) {
diags = model.ACL.ElementsAs(ctx, &acl, false)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
err := r.loadPlanId(ctx, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err))
@ -376,7 +442,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
return
}
err = mapFields(ctx, waitResp, &model)
err = mapFields(ctx, waitResp, nil, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err))
return
@ -386,6 +452,33 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
if resp.Diagnostics.HasError() {
return
}
// Update ACL
err = updateACL(ctx, projectId, instanceId, acl, r.client)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Updating ACL: %v", err))
return
}
aclList, err := r.client.ListACL(ctx, instanceId, projectId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API to list ACL data: %v", err))
return
}
// Map response body to schema
err = mapFields(ctx, waitResp, aclList, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing ACL API payload: %v", err))
return
}
// Set state to ACL populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Argus instance updated")
}
@ -435,7 +528,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS
tflog.Info(ctx, "Argus instance state imported")
}
func mapFields(ctx context.Context, r *argus.GetInstanceResponse, model *Model) error {
func mapFields(ctx context.Context, r *argus.GetInstanceResponse, acl *argus.ListACLResponse, model *Model) error {
if r == nil {
return fmt.Errorf("response input is nil")
}
@ -500,6 +593,37 @@ func mapFields(ctx context.Context, r *argus.GetInstanceResponse, model *Model)
model.OtlpTracesURL = types.StringPointerValue(i.OtlpTracesUrl)
model.ZipkinSpansURL = types.StringPointerValue(i.ZipkinSpansUrl)
}
err := mapACLField(acl, model)
if err != nil {
return err
}
return nil
}
func mapACLField(aclList *argus.ListACLResponse, model *Model) error {
if aclList == nil {
if model.ACL.IsNull() || model.ACL.IsUnknown() {
model.ACL = types.SetNull(types.StringType)
}
return nil
}
if aclList.Acl == nil || len(*aclList.Acl) == 0 {
model.ACL = types.SetNull(types.StringType)
return nil
}
acl := []attr.Value{}
for _, cidr := range *aclList.Acl {
acl = append(acl, types.StringValue(cidr))
}
aclTF, diags := types.SetValue(types.StringType, acl)
if diags.HasError() {
return fmt.Errorf("mapping ACL: %w", core.DiagsToError(diags))
}
model.ACL = aclTF
return nil
}
@ -519,6 +643,19 @@ func toCreatePayload(model *Model) (*argus.CreateInstancePayload, error) {
}, nil
}
func updateACL(ctx context.Context, projectId, instanceId string, acl []string, client *argus.APIClient) error {
payload := argus.UpdateACLPayload{
Acl: utils.Ptr(acl),
}
_, err := client.UpdateACL(ctx, instanceId, projectId).UpdateACLPayload(payload).Execute()
if err != nil {
return fmt.Errorf("updating ACL: %w", err)
}
return nil
}
func toUpdatePayload(model *Model) (*argus.UpdateInstancePayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")

View file

@ -14,16 +14,18 @@ import (
func TestMapFields(t *testing.T) {
tests := []struct {
description string
input *argus.GetInstanceResponse
expected Model
isValid bool
description string
instanceResp *argus.GetInstanceResponse
listACLResp *argus.ListACLResponse
expected Model
isValid bool
}{
{
"default_ok",
&argus.GetInstanceResponse{
Id: utils.Ptr("iid"),
},
nil,
Model{
Id: types.StringValue("pid,iid"),
ProjectId: types.StringValue("pid"),
@ -32,6 +34,7 @@ func TestMapFields(t *testing.T) {
PlanName: types.StringNull(),
Name: types.StringNull(),
Parameters: types.MapNull(types.StringType),
ACL: types.SetNull(types.StringType),
},
true,
},
@ -44,6 +47,12 @@ func TestMapFields(t *testing.T) {
PlanId: utils.Ptr("planId"),
Parameters: &map[string]string{"key": "value"},
},
&argus.ListACLResponse{
Acl: &[]string{
"1.1.1.1/32",
},
Message: utils.Ptr("message"),
},
Model{
Id: types.StringValue("pid,iid"),
ProjectId: types.StringValue("pid"),
@ -52,6 +61,40 @@ func TestMapFields(t *testing.T) {
PlanId: types.StringValue("planId"),
PlanName: types.StringValue("plan1"),
Parameters: toTerraformStringMapMust(context.Background(), map[string]string{"key": "value"}),
ACL: types.SetValueMust(types.StringType, []attr.Value{
types.StringValue("1.1.1.1/32"),
}),
},
true,
},
{
"values_ok_multiple_acls",
&argus.GetInstanceResponse{
Id: utils.Ptr("iid"),
Name: utils.Ptr("name"),
PlanName: utils.Ptr("plan1"),
PlanId: utils.Ptr("planId"),
Parameters: &map[string]string{"key": "value"},
},
&argus.ListACLResponse{
Acl: &[]string{
"1.1.1.1/32",
"8.8.8.8/32",
},
Message: utils.Ptr("message"),
},
Model{
Id: types.StringValue("pid,iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringValue("name"),
InstanceId: types.StringValue("iid"),
PlanId: types.StringValue("planId"),
PlanName: types.StringValue("plan1"),
Parameters: toTerraformStringMapMust(context.Background(), map[string]string{"key": "value"}),
ACL: types.SetValueMust(types.StringType, []attr.Value{
types.StringValue("1.1.1.1/32"),
types.StringValue("8.8.8.8/32"),
}),
},
true,
},
@ -61,6 +104,10 @@ func TestMapFields(t *testing.T) {
Id: utils.Ptr("iid"),
Name: nil,
},
&argus.ListACLResponse{
Acl: &[]string{},
Message: nil,
},
Model{
Id: types.StringValue("pid,iid"),
ProjectId: types.StringValue("pid"),
@ -69,18 +116,21 @@ func TestMapFields(t *testing.T) {
PlanName: types.StringNull(),
Name: types.StringNull(),
Parameters: types.MapNull(types.StringType),
ACL: types.SetNull(types.StringType),
},
true,
},
{
"response_nil_fail",
nil,
nil,
Model{},
false,
},
{
"no_resource_id",
&argus.GetInstanceResponse{},
nil,
Model{},
false,
},
@ -90,7 +140,7 @@ func TestMapFields(t *testing.T) {
state := &Model{
ProjectId: tt.expected.ProjectId,
}
err := mapFields(context.Background(), tt.input, state)
err := mapFields(context.Background(), tt.instanceResp, tt.listACLResp, state)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}