From 1646476d5610b7c5c85988a71a71066c9c4e02c4 Mon Sep 17 00:00:00 2001 From: Rajagopalan Subrahmanian Date: Thu, 11 Jul 2024 03:47:31 -0400 Subject: [PATCH 1/4] add the code and test for the telemetry service registry entry providers --- .../telemetry_service_registry_entry.go | 125 +++++++++ ...urce_telemetry_service_registry_entries.go | 87 ++++++ ...source_telemetry_service_registry_entry.go | 71 +++++ ...e_telemetry_service_registry_entry_test.go | 61 ++++ apstra/provider.go | 3 + ...source_telemetry_service_registry_entry.go | 178 ++++++++++++ ...e_telemetry_service_registry_entry_test.go | 261 ++++++++++++++++++ .../telemetry_service_registry_entry.go | 80 ++++++ .../telemetry_service_registry_entries.md | 145 ++++++++++ .../telemetry_service_registry_entry.md | 71 +++++ .../telemetry_service_registry_entry.md | 109 ++++++++ .../example.tf | 119 ++++++++ .../example.tf | 38 +++ .../example.tf | 72 +++++ 14 files changed, 1420 insertions(+) create mode 100644 apstra/analytics/telemetry_service_registry_entry.go create mode 100644 apstra/data_source_telemetry_service_registry_entries.go create mode 100644 apstra/data_source_telemetry_service_registry_entry.go create mode 100644 apstra/data_source_telemetry_service_registry_entry_test.go create mode 100644 apstra/resource_telemetry_service_registry_entry.go create mode 100644 apstra/resource_telemetry_service_registry_entry_test.go create mode 100644 apstra/test_utils/telemetry_service_registry_entry.go create mode 100644 docs/data-sources/telemetry_service_registry_entries.md create mode 100644 docs/data-sources/telemetry_service_registry_entry.md create mode 100644 docs/resources/telemetry_service_registry_entry.md create mode 100644 examples/data-sources/apstra_telemetry_service_registry_entries/example.tf create mode 100644 examples/data-sources/apstra_telemetry_service_registry_entry/example.tf create mode 100644 examples/resources/apstra_telemetry_service_registry_entry/example.tf diff --git a/apstra/analytics/telemetry_service_registry_entry.go b/apstra/analytics/telemetry_service_registry_entry.go new file mode 100644 index 00000000..bdd91952 --- /dev/null +++ b/apstra/analytics/telemetry_service_registry_entry.go @@ -0,0 +1,125 @@ +package analytics + +import ( + "context" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type TelemetryServiceRegistryEntry struct { + ServiceName types.String `tfsdk:"service_name"` + ApplicationSchema types.String `tfsdk:"application_schema"` + StorageSchemaPath types.String `tfsdk:"storage_schema_path"` + Builtin types.Bool `tfsdk:"built_in"` + Description types.String `tfsdk:"description"` + Version types.String `tfsdk:"version"` +} + +func (o TelemetryServiceRegistryEntry) ResourceAttributes() map[string]resourceSchema.Attribute { + return map[string]resourceSchema.Attribute{ + "service_name": resourceSchema.StringAttribute{ + MarkdownDescription: "Service Name. Used to identify the Service.", + Required: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "application_schema": resourceSchema.StringAttribute{ + MarkdownDescription: "Application Schema expressed in Json schema", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "storage_schema_path": resourceSchema.StringAttribute{ + MarkdownDescription: "Storage Schema Path", + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + }, + "description": resourceSchema.StringAttribute{ + MarkdownDescription: "Description", + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + }, + "version": resourceSchema.StringAttribute{ + MarkdownDescription: "Version", + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "built_in": resourceSchema.BoolAttribute{ + MarkdownDescription: "True If built in.", + Computed: true, + }, + } +} + +func (o TelemetryServiceRegistryEntry) DataSourceAttributes() map[string]dataSourceSchema.Attribute { + return map[string]dataSourceSchema.Attribute{ + "service_name": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Service Name. Used to identify the Service.", + Required: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + }, + "application_schema": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Application Schema expressed in Json schema", + Computed: true, + }, + "storage_schema_path": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Storage Schema Path", + Computed: true, + }, + "description": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Description", + Computed: true, + }, + "version": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Version", + Computed: true, + }, + "built_in": dataSourceSchema.BoolAttribute{ + MarkdownDescription: "True If built in.", + Computed: true, + }, + } +} + +func (o *TelemetryServiceRegistryEntry) LoadApiData(ctx context.Context, in *apstra.TelemetryServiceRegistryEntry, diag *diag.Diagnostics) { + o.ServiceName = types.StringValue(in.ServiceName) + o.Version = types.StringValue(in.Version) + o.Description = utils.StringValueOrNull(ctx, in.Description, diag) + o.Builtin = types.BoolValue(in.Builtin) + o.ApplicationSchema = types.StringValue(string(in.ApplicationSchema)) + o.StorageSchemaPath = types.StringValue(in.StorageSchemaPath.String()) +} + +func (o *TelemetryServiceRegistryEntry) Request(ctx context.Context, d *diag.Diagnostics) *apstra.TelemetryServiceRegistryEntry { + var s apstra.StorageSchemaPath + e := s.FromString(o.StorageSchemaPath.ValueString()) + if e != nil { + d.AddError("Failed to Parse Storage Schema Path", e.Error()) + return nil + } + return &apstra.TelemetryServiceRegistryEntry{ + ServiceName: o.ServiceName.ValueString(), + ApplicationSchema: []byte(o.ApplicationSchema.ValueString()), + StorageSchemaPath: s, + Builtin: o.Builtin.ValueBool(), + Description: o.Description.ValueString(), + Version: o.Version.ValueString(), + } +} diff --git a/apstra/data_source_telemetry_service_registry_entries.go b/apstra/data_source_telemetry_service_registry_entries.go new file mode 100644 index 00000000..16c6f7e9 --- /dev/null +++ b/apstra/data_source_telemetry_service_registry_entries.go @@ -0,0 +1,87 @@ +package tfapstra + +import ( + "context" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigure = &dataSourceTelemetryServiceRegistryEntries{} +var _ datasourceWithSetClient = &dataSourceTelemetryServiceRegistryEntries{} + +type dataSourceTelemetryServiceRegistryEntries struct { + client *apstra.Client +} + +func (o *dataSourceTelemetryServiceRegistryEntries) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_telemetry_service_registry_entries" +} + +func (o *dataSourceTelemetryServiceRegistryEntries) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + configureDataSource(ctx, o, req, resp) +} + +func (o *dataSourceTelemetryServiceRegistryEntries) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: docCategoryDesign + "This data source returns the Service Names of all Telemetry Service Registry Entries.", + Attributes: map[string]schema.Attribute{ + "service_names": schema.SetAttribute{ + MarkdownDescription: "A set of Apstra object ID numbers.", + Computed: true, + ElementType: types.StringType, + }, + "built_in": schema.BoolAttribute{ + MarkdownDescription: "Return only built_in if true, not built_in if false, all otherwise", + Optional: true, + }, + }, + } +} + +func (o *dataSourceTelemetryServiceRegistryEntries) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config struct { + ServiceNames types.Set `tfsdk:"service_names"` + BuiltIn types.Bool `tfsdk:"built_in"` + } + + // get the configuration + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + var err error + tses, err := o.client.GetAllTelemetryServiceRegistryEntries(ctx) + if err != nil { + resp.Diagnostics.AddError("error retrieving Property Set IDs", err.Error()) + return + } + var snames []string + for _, t := range tses { + if config.BuiltIn.IsUnknown() || config.BuiltIn.IsNull() || config.BuiltIn.ValueBool() == t.Builtin { + snames = append(snames, t.ServiceName) + } + } + + snameSet, diags := types.SetValueFrom(ctx, types.StringType, snames) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // create new state object + var state struct { + ServiceNames types.Set `tfsdk:"service_names"` + BuiltIn types.Bool `tfsdk:"built_in"` + } + state.ServiceNames = snameSet + state.BuiltIn = config.BuiltIn + // set state + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (o *dataSourceTelemetryServiceRegistryEntries) setClient(client *apstra.Client) { + o.client = client +} diff --git a/apstra/data_source_telemetry_service_registry_entry.go b/apstra/data_source_telemetry_service_registry_entry.go new file mode 100644 index 00000000..c96e7900 --- /dev/null +++ b/apstra/data_source_telemetry_service_registry_entry.go @@ -0,0 +1,71 @@ +package tfapstra + +import ( + "context" + "fmt" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/analytics" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" +) + +var _ datasource.DataSourceWithConfigure = &dataSourceTelemetryServiceRegistryEntry{} +var _ datasourceWithSetClient = &dataSourceTelemetryServiceRegistryEntry{} + +type dataSourceTelemetryServiceRegistryEntry struct { + client *apstra.Client +} + +func (o *dataSourceTelemetryServiceRegistryEntry) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_telemetry_service_registry_entry" +} + +func (o *dataSourceTelemetryServiceRegistryEntry) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + configureDataSource(ctx, o, req, resp) +} + +func (o *dataSourceTelemetryServiceRegistryEntry) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: docCategoryDesign + "This data source provides details of a specific TelemetryServiceRegistryEntry.\n\n" + + "At least one optional attribute is required.", + Attributes: analytics.TelemetryServiceRegistryEntry{}.DataSourceAttributes(), + } +} + +func (o *dataSourceTelemetryServiceRegistryEntry) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config analytics.TelemetryServiceRegistryEntry + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + var err error + var api *apstra.TelemetryServiceRegistryEntry + api, err = o.client.GetTelemetryServiceRegistryEntry(ctx, config.ServiceName.ValueString()) + if utils.IsApstra404(err) { + resp.Diagnostics.AddAttributeError( + path.Root("name"), + "TelemetryServiceRegistryEntry not found", + fmt.Sprintf("TelemetryServiceRegistryEntry with Name %q not found", config.ServiceName.ValueString())) + return + } + if err != nil { // catch errors other than 404 from above + resp.Diagnostics.AddError("Error retrieving TelemetryServiceRegistryEntry", err.Error()) + return + } + + // create new state object + var state analytics.TelemetryServiceRegistryEntry + state.LoadApiData(ctx, api, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + // Set state + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (o *dataSourceTelemetryServiceRegistryEntry) setClient(client *apstra.Client) { + o.client = client +} diff --git a/apstra/data_source_telemetry_service_registry_entry_test.go b/apstra/data_source_telemetry_service_registry_entry_test.go new file mode 100644 index 00000000..6b09a241 --- /dev/null +++ b/apstra/data_source_telemetry_service_registry_entry_test.go @@ -0,0 +1,61 @@ +package tfapstra + +import ( + "context" + "errors" + "fmt" + testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "strings" + "testing" +) + +const ( + dataSourceTelemetryServiceRegistryByServiceNameHCL = ` +data "apstra_telemetry_service_registry_entry" "test" { + service_name = "%s" +} +` +) + +func TestAccDataSourceTelemetryServiceRegistryEntry(t *testing.T) { + ctx := context.Background() + + ts := testutils.TelemetryServiceRegistryEntryA(t, ctx) + + TestAppSchema := func(state string) error { + var diags diag.Diagnostics + if !utils.JSONEqual(types.StringValue(state), types.StringValue(string(ts.ApplicationSchema)), &diags) { + return fmt.Errorf("input schema does not match output Input %v. Output %v", ts.ApplicationSchema, state) + } + if diags.HasError() { + var sb strings.Builder + for _, d := range diags.Errors() { + sb.WriteString(d.Summary() + "\n") + sb.WriteString(d.Detail() + "\n") + } + return errors.New(sb.String()) + } + return nil + } + + resource.Test(t, resource.TestCase{ + //PreCheck: setup, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Read by ID + { + Config: insecureProviderConfigHCL + fmt.Sprintf(dataSourceTelemetryServiceRegistryByServiceNameHCL, ts.ServiceName), + Check: resource.ComposeAggregateTestCheckFunc( + // Verify data source/resource fields match + resource.TestCheckResourceAttr("data.apstra_telemetry_service_registry_entry.test", "service_name", ts.ServiceName), + resource.TestCheckResourceAttr("data.apstra_telemetry_service_registry_entry.test", "storage_schema_path", ts.StorageSchemaPath.String()), + resource.TestCheckResourceAttrWith("data.apstra_telemetry_service_registry_entry.test", "application_schema", TestAppSchema), + ), + }, + }, + }) +} diff --git a/apstra/provider.go b/apstra/provider.go index dd678cce..b5c23535 100644 --- a/apstra/provider.go +++ b/apstra/provider.go @@ -515,6 +515,8 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource func() datasource.DataSource { return &dataSourceRackType{} }, func() datasource.DataSource { return &dataSourceRackTypes{} }, func() datasource.DataSource { return &dataSourceTag{} }, + func() datasource.DataSource { return &dataSourceTelemetryServiceRegistryEntry{} }, + func() datasource.DataSource { return &dataSourceTelemetryServiceRegistryEntries{} }, func() datasource.DataSource { return &dataSourceTemplateCollapsed{} }, func() datasource.DataSource { return &dataSourceTemplatePodBased{} }, func() datasource.DataSource { return &dataSourceTemplateRackBased{} }, @@ -563,6 +565,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource { func() resource.Resource { return &resourcePropertySet{} }, func() resource.Resource { return &resourceRackType{} }, func() resource.Resource { return &resourceTag{} }, + func() resource.Resource { return &resourceTelemetryServiceRegistryEntry{} }, func() resource.Resource { return &resourceTemplateCollapsed{} }, func() resource.Resource { return &resourceTemplatePodBased{} }, func() resource.Resource { return &resourceTemplateRackBased{} }, diff --git a/apstra/resource_telemetry_service_registry_entry.go b/apstra/resource_telemetry_service_registry_entry.go new file mode 100644 index 00000000..0a54ec01 --- /dev/null +++ b/apstra/resource_telemetry_service_registry_entry.go @@ -0,0 +1,178 @@ +package tfapstra + +import ( + "context" + "fmt" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/analytics" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ resource.ResourceWithConfigure = &resourceTelemetryServiceRegistryEntry{} +var _ resourceWithSetClient = &resourceTelemetryServiceRegistryEntry{} + +type resourceTelemetryServiceRegistryEntry struct { + client *apstra.Client +} + +func (o *resourceTelemetryServiceRegistryEntry) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_telemetry_service_registry_entry" +} + +func (o *resourceTelemetryServiceRegistryEntry) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + configureResource(ctx, o, req, resp) +} + +func (o *resourceTelemetryServiceRegistryEntry) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: docCategoryDesign + "This resource creates a Property Set in the Apstra Design tab.", + Attributes: analytics.TelemetryServiceRegistryEntry{}.ResourceAttributes(), + } +} + +func (o *resourceTelemetryServiceRegistryEntry) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var plan analytics.TelemetryServiceRegistryEntry + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // Convert the plan into an API Request + tsRequest := plan.Request(ctx, &resp.Diagnostics) + // Created Registry Entry will not be builtin + plan.Builtin = types.BoolValue(false) + if plan.Version.IsUnknown() { + plan.Version = types.StringNull() + } + if resp.Diagnostics.HasError() { + return + } + _, err := o.client.CreateTelemetryServiceRegistryEntry(ctx, tsRequest) + if err != nil { + resp.Diagnostics.AddError("error creating new TelemetryServiceRegistryEntry", err.Error()) + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (o *resourceTelemetryServiceRegistryEntry) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state analytics.TelemetryServiceRegistryEntry + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + var err error + var api *apstra.TelemetryServiceRegistryEntry + + api, err = o.client.GetTelemetryServiceRegistryEntry(ctx, state.ServiceName.ValueString()) + if utils.IsApstra404(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { // catch errors other than 404 from above + resp.Diagnostics.AddError("Error retrieving TelemetryServiceRegistryEntry", err.Error()) + return + } + + // create new state object + var newstate analytics.TelemetryServiceRegistryEntry + newstate.LoadApiData(ctx, api, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + if utils.JSONEqual(newstate.ApplicationSchema, state.ApplicationSchema, &resp.Diagnostics) { + newstate.ApplicationSchema = state.ApplicationSchema + } + if resp.Diagnostics.HasError() { + return + } + // Set state + // + resp.Diagnostics.Append(resp.State.Set(ctx, &newstate)...) +} + +// Update resource +func (o *resourceTelemetryServiceRegistryEntry) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // Get plan values + var cfg, plan analytics.TelemetryServiceRegistryEntry + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(req.Config.Get(ctx, &cfg)...) + if resp.Diagnostics.HasError() { + return + } + + if cfg.ServiceName != plan.ServiceName { + resp.Diagnostics.AddError("Cannot Change Service Name", fmt.Sprintf("Was %s New Value %s", cfg.ServiceName.ValueString(), plan.ServiceName.ValueString())) + return + } + tsReq := plan.Request(ctx, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + // Update Property Set + err := o.client.UpdateTelemetryServiceRegistryEntry(ctx, plan.ServiceName.ValueString(), tsReq) + if err != nil { + resp.Diagnostics.AddError("error updating Property Set", err.Error()) + return + } + + // read the state fromm the API + api, err := o.client.GetTelemetryServiceRegistryEntry(ctx, plan.ServiceName.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + resp.Diagnostics.AddAttributeError( + path.Root("id"), + "TelemetryServiceRegistryEntry not found", + fmt.Sprintf("just-updated TelemetryServiceRegistryEntry with Service Name %q not found.", plan.ServiceName.ValueString())) + return + } + resp.Diagnostics.AddError("error updating Telemetry Service Registry Entry set", err.Error()) + return + } + + // Do the Get dance so that in case the application schema is stored differently the next + // Read() does not confuse terraform + as := plan.ApplicationSchema + plan.LoadApiData(ctx, api, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + if utils.JSONEqual(plan.ApplicationSchema, as, &resp.Diagnostics) { + plan.ApplicationSchema = as + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +// Delete resource +func (o *resourceTelemetryServiceRegistryEntry) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state analytics.TelemetryServiceRegistryEntry + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // Delete Property Set by calling API + err := o.client.DeleteTelemetryServiceRegistryEntry(ctx, state.ServiceName.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + return // 404 is okay + } + resp.Diagnostics.AddError("error deleting Property Set", err.Error()) + return + } +} + +func (o *resourceTelemetryServiceRegistryEntry) setClient(client *apstra.Client) { + o.client = client +} diff --git a/apstra/resource_telemetry_service_registry_entry_test.go b/apstra/resource_telemetry_service_registry_entry_test.go new file mode 100644 index 00000000..5926d122 --- /dev/null +++ b/apstra/resource_telemetry_service_registry_entry_test.go @@ -0,0 +1,261 @@ +package tfapstra + +import ( + "fmt" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "testing" +) + +const ( + resourceTelemetryServiceRegistryEntryHCL = ` +// resource config +resource "apstra_telemetry_service_registry_entry" "test" { + description = "Test Registry Entry" + service_name = "%s" + application_schema = jsonencode(%s) + storage_schema_path = "%s" + +} +` + as1 = `{ + properties = { + key = { + properties = { + authenticated_vlan = { + type = "string" + } + authorization_status = { + type = "string" + } + fallback_vlan_active = { + enum = [ + "True", + "False", + ] + type = "string" + } + port_status = { + enum = [ + "authorized", + "blocked", + ] + type = "string" + } + supplicant_mac = { + pattern = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" + type = "string" + } + } + required = [ + "supplicant_mac", + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active", + ] + type = "object" + } + value = { + description = "0 in case of blocked, 1 in case of authorized" + type = "integer" + } + } + required = [ + "key", + "value", + ] + type = "object" + }` + as2 = `{ + properties = { + key = { + properties = { + authenticated_vlan = { + type = "string" + } + authorization_status = { + type = "string" + } + fallback_vlan_active = { + enum = [ + "True", + "False", + ] + type = "string" + } + port_status = { + enum = [ + "authorized", + "blocked", + ] + type = "string" + } + } + required = [ + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active", + ] + type = "object" + } + value = { + description = "0 in case of blocked, 1 in case of authorized" + type = "string" + } + } + required = [ + "key", + "value", + ] + type = "object" + }` + as1_string = `{ + "properties":{ + "key":{ + "properties":{ + "authenticated_vlan":{ + "type":"string" + }, + "authorization_status":{ + "type":"string" + }, + "fallback_vlan_active":{ + "enum":[ + "True", + "False" + ], + "type":"string" + }, + "port_status":{ + "enum":[ + "authorized", + "blocked" + ], + "type":"string" + }, + "supplicant_mac":{ + "pattern":"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$", + "type":"string" + } + }, + "required":[ + "supplicant_mac", + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active" + ], + "type":"object" + }, + "value":{ + "description":"0 in case of blocked, 1 in case of authorized", + "type":"integer" + } + }, + "required":[ + "key", + "value" + ], + "type":"object" + }` + as2_string = `{ + "properties":{ + "key":{ + "properties":{ + "authenticated_vlan":{ + "type":"string" + }, + "authorization_status":{ + "type":"string" + }, + "fallback_vlan_active":{ + "enum":[ + "True", + "False" + ], + "type":"string" + }, + "port_status":{ + "enum":[ + "authorized", + "blocked" + ], + "type":"string" + } + }, + "required":[ + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active" + ], + "type":"object" + }, + "value":{ + "description":"0 in case of blocked, 1 in case of authorized", + "type":"string" + } + }, + "required":[ + "key", + "value" + ], + "type":"object" + }` + ss1 = "aos.sdk.telemetry.schemas.iba_integer_data" + ss2 = "aos.sdk.telemetry.schemas.iba_string_data" +) + +func TestAccResourceTelemetryServiceRegistryEntry(t *testing.T) { + var ( + testAccResourceServiceName = acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + testAccResourceServiceRegistryCfg1 = fmt.Sprintf(resourceTelemetryServiceRegistryEntryHCL, testAccResourceServiceName, as1, ss1) + testAccResourceServiceRegistryCfg2 = fmt.Sprintf(resourceTelemetryServiceRegistryEntryHCL, testAccResourceServiceName, as2, ss2) + ) + + d := diag.Diagnostics{} + TestSR1 := func(state string) error { + if !utils.JSONEqual(types.StringValue(state), types.StringValue(as1_string), &d) { + return fmt.Errorf("input Data does not match output Input %v. Output %v", as1_string, state) + } + return nil + } + + TestSR2 := func(state string) error { + if !utils.JSONEqual(types.StringValue(state), types.StringValue(as2_string), &d) { + return fmt.Errorf("input Data does not match output Input %v. Output %v", as2_string, state) + } + return nil + } + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: insecureProviderConfigHCL + testAccResourceServiceRegistryCfg1, + Check: resource.ComposeAggregateTestCheckFunc( + // Verify name and data + resource.TestCheckResourceAttr("apstra_telemetry_service_registry_entry.test", "service_name", testAccResourceServiceName), + resource.TestCheckResourceAttr("apstra_telemetry_service_registry_entry.test", "storage_schema_path", ss1), + resource.TestCheckResourceAttrWith("apstra_telemetry_service_registry_entry.test", "application_schema", TestSR1), + ), + }, + // Update and Read testing + { + Config: insecureProviderConfigHCL + testAccResourceServiceRegistryCfg2, + Check: resource.ComposeAggregateTestCheckFunc( + // Verify name and data + resource.TestCheckResourceAttr("apstra_telemetry_service_registry_entry.test", "service_name", testAccResourceServiceName), + resource.TestCheckResourceAttr("apstra_telemetry_service_registry_entry.test", "storage_schema_path", ss2), + resource.TestCheckResourceAttrWith("apstra_telemetry_service_registry_entry.test", "application_schema", TestSR2), + ), + }, + }, + }) +} diff --git a/apstra/test_utils/telemetry_service_registry_entry.go b/apstra/test_utils/telemetry_service_registry_entry.go new file mode 100644 index 00000000..f9498377 --- /dev/null +++ b/apstra/test_utils/telemetry_service_registry_entry.go @@ -0,0 +1,80 @@ +package testutils + +import ( + "context" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/stretchr/testify/require" + "testing" +) + +func TelemetryServiceRegistryEntryA(t testing.TB, ctx context.Context) *apstra.TelemetryServiceRegistryEntry { + t.Helper() + + client := GetTestClient(t, ctx) + schema := []byte(`{ + "required": ["key","value"], + "type": "object", + "properties": { + "value": { + "type": "integer", + "description": "0 in case of blocked, 1 in case of authorized" + }, + "key": { + "required": [ + "supplicant_mac", + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active" + ], + "type": "object", + "properties": { + "supplicant_mac": { + "type": "string", + "pattern": "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" + }, + "authenticated_vlan": { + "type": "string" + }, + "authorization_status": { + "type": "string" + }, + "port_status": { + "enum": [ + "authorized", + "blocked" + ], + "type": "string" + }, + "fallback_vlan_active": { + "enum": [ + "True", + "False" + ], + "type": "string" + } + } + } + } + }`) + request := apstra.TelemetryServiceRegistryEntry{ + ServiceName: "TestTelemetryServiceA", + ApplicationSchema: schema, + StorageSchemaPath: apstra.StorageSchemaPathIBA_INTEGER_DATA, + Builtin: false, + Description: "Test Telemetry Service A", + Version: "", + } + ts, err := client.GetTelemetryServiceRegistryEntry(ctx, "TestTelemetryServiceA") + if ts != nil { + return ts + } + sn, err := client.CreateTelemetryServiceRegistryEntry(ctx, &request) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, client.DeleteTelemetryServiceRegistryEntry(ctx, sn)) }) + + ts, err = client.GetTelemetryServiceRegistryEntry(ctx, sn) + require.NoError(t, err) + + return ts +} diff --git a/docs/data-sources/telemetry_service_registry_entries.md b/docs/data-sources/telemetry_service_registry_entries.md new file mode 100644 index 00000000..212072a2 --- /dev/null +++ b/docs/data-sources/telemetry_service_registry_entries.md @@ -0,0 +1,145 @@ +--- +page_title: "apstra_telemetry_service_registry_entries Data Source - terraform-provider-apstra" +subcategory: "Design" +description: |- + This data source returns the Service Names of all Telemetry Service Registry Entries. +--- + +# apstra_telemetry_service_registry_entries (Data Source) + +This data source returns the Service Names of all Telemetry Service Registry Entries. + + +## Example Usage + +```terraform +# The following example shows getting a list of +# Apstra Telemetry Service Registy Entries + +# Get all Entries +data "apstra_telemetry_service_registry_entries" "all" { +} +output "all_entries"{ + value = data.apstra_telemetry_service_registry_entries.all +} + +#Get only built-in Entries +data "apstra_telemetry_service_registry_entries" "builtin" { + built_in = true +} +output "builtin_entries"{ + value = data.apstra_telemetry_service_registry_entries.builtin +} + +#Get Only non-built-in Entries +data "apstra_telemetry_service_registry_entries" "not_builtin" { + built_in = false +} +output "not_builtin_entries"{ + value = data.apstra_telemetry_service_registry_entries.not_builtin +} + +#Output will look something like this +#Outputs: +# +#all_entries = { +#"built_in" = tobool(null) +#"service_names" = toset([ +#"TestTelemetryServiceA", +#"TestTelemetryServiceC", +#"arp", +#"bgp", +#"bgp_communities", +#"bgp_route", +#"blueprint_collector", +#"disk_util", +#"dot1x", +#"dot1x_hosts", +#"environment", +#"evpn_host_flap", +#"evpn_host_flap_count", +#"evpn_vxlan_type1", +#"evpn_vxlan_type3", +#"evpn_vxlan_type4", +#"evpn_vxlan_type5", +#"hostname", +#"interface", +#"interface_counters", +#"lag", +#"lldp", +#"mac", +#"mlag", +#"multiagent_detector", +#"nsxt", +#"optical_xcvr", +#"ospf_state", +#"poe_controller", +#"poe_interfaces", +#"resource_util", +#"route", +#"route_lookup", +#"shared_tunnel_mode", +#"virtual_infra", +#"vxlan_floodlist", +#"xcvr", +#]) +#} +#builtin_entries = { +#"built_in" = true +#"service_names" = toset([ +#"arp", +#"bgp", +#"bgp_communities", +#"bgp_route", +#"blueprint_collector", +#"disk_util", +#"dot1x", +#"dot1x_hosts", +#"environment", +#"evpn_host_flap", +#"evpn_host_flap_count", +#"evpn_vxlan_type1", +#"evpn_vxlan_type3", +#"evpn_vxlan_type4", +#"evpn_vxlan_type5", +#"hostname", +#"interface", +#"interface_counters", +#"lag", +#"lldp", +#"mac", +#"mlag", +#"multiagent_detector", +#"nsxt", +#"optical_xcvr", +#"ospf_state", +#"poe_controller", +#"poe_interfaces", +#"resource_util", +#"route", +#"route_lookup", +#"shared_tunnel_mode", +#"virtual_infra", +#"vxlan_floodlist", +#"xcvr", +#]) +#} +#not_builtin_entries = { +#"built_in" = false +#"service_names" = toset([ +#"TestTelemetryServiceA", +#"TestTelemetryServiceC", +#]) +#} +``` + + +## Schema + +### Optional + +- `built_in` (Boolean) Return only built_in if true, not built_in if false, all otherwise + +### Read-Only + +- `service_names` (Set of String) A set of Apstra object ID numbers. diff --git a/docs/data-sources/telemetry_service_registry_entry.md b/docs/data-sources/telemetry_service_registry_entry.md new file mode 100644 index 00000000..03e3610e --- /dev/null +++ b/docs/data-sources/telemetry_service_registry_entry.md @@ -0,0 +1,71 @@ +--- +page_title: "apstra_telemetry_service_registry_entry Data Source - terraform-provider-apstra" +subcategory: "Design" +description: |- + This data source provides details of a specific TelemetryServiceRegistryEntry. + At least one optional attribute is required. +--- + +# apstra_telemetry_service_registry_entry (Data Source) + +This data source provides details of a specific TelemetryServiceRegistryEntry. + +At least one optional attribute is required. + + +## Example Usage + +```terraform +# The following example shows getting a list of +# Apstra Telemetry Service Registy Entries + +#Get Only non-built-in Entries +data "apstra_telemetry_service_registry_entries" "not_builtin" { + built_in = false +} + +data "apstra_telemetry_service_registry_entry" "all_not_built_in" { + for_each = data.apstra_telemetry_service_registry_entries.not_builtin.service_names + service_name = each.value +} + +output "not_built_in_emtry" { + value = data.apstra_telemetry_service_registry_entry.all_not_built_in +} + +#Output looks something like this. +#Outputs +#not_built_in_emtry = { +# "TestTelemetryServiceA" = { +# "application_schema" = "{\"properties\": {\"key\": {\"properties\": {\"authenticated_vlan\": {\"type\": \"string\"}, \"authorization_status\": {\"type\": \"string\"}, \"fallback_vlan_active\": {\"enum\": [\"True\", \"False\"], \"type\": \"string\"}, \"port_status\": {\"enum\": [\"authorized\", \"blocked\"], \"type\": \"string\"}, \"supplicant_mac\": {\"pattern\": \"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\", \"type\": \"string\"}}, \"required\": [\"supplicant_mac\", \"authenticated_vlan\", \"authorization_status\", \"port_status\", \"fallback_vlan_active\"], \"type\": \"object\"}, \"value\": {\"description\": \"0 in case of blocked, 1 in case of authorized\", \"type\": \"integer\"}}, \"required\": [\"key\", \"value\"], \"type\": \"object\"}" +# "built_in" = false +# "description" = "Test Telemetry Service A" +# "service_name" = "TestTelemetryServiceA" +# "storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +# "version" = "" +# } +# "TestTelemetryServiceC" = { +# "application_schema" = "{\"properties\": {\"key\": {\"properties\": {\"authenticated_vlan\": {\"type\": \"string\"}, \"authorization_status\": {\"type\": \"string\"}, \"fallback_vlan_active\": {\"enum\": [\"True\", \"False\"], \"type\": \"string\"}, \"port_status\": {\"enum\": [\"authorized\", \"blocked\"], \"type\": \"string\"}, \"supplicant_mac\": {\"pattern\": \"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\", \"type\": \"string\"}}, \"required\": [\"supplicant_mac\", \"authenticated_vlan\", \"authorization_status\", \"port_status\", \"fallback_vlan_active\"], \"type\": \"object\"}, \"value\": {\"description\": \"0 in case of blocked, 1 in case of authorized\", \"type\": \"integer\"}}, \"required\": [\"key\", \"value\"], \"type\": \"object\"}" +# "built_in" = false +# "description" = "Test Telemetry Service B" +# "service_name" = "TestTelemetryServiceC" +# "storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +# "version" = "" +# } +#} +``` + + +## Schema + +### Required + +- `service_name` (String) Service Name. Used to identify the Service. + +### Read-Only + +- `application_schema` (String) Application Schema expressed in Json schema +- `built_in` (Boolean) True If built in. +- `description` (String) Description +- `storage_schema_path` (String) Storage Schema Path +- `version` (String) Version diff --git a/docs/resources/telemetry_service_registry_entry.md b/docs/resources/telemetry_service_registry_entry.md new file mode 100644 index 00000000..8a4a79d6 --- /dev/null +++ b/docs/resources/telemetry_service_registry_entry.md @@ -0,0 +1,109 @@ +--- +page_title: "apstra_telemetry_service_registry_entry Resource - terraform-provider-apstra" +subcategory: "Design" +description: |- + This resource creates a Property Set in the Apstra Design tab. +--- + +# apstra_telemetry_service_registry_entry (Resource) + +This resource creates a Property Set in the Apstra Design tab. + + +## Example Usage + +```terraform +resource "apstra_telemetry_service_registry_entry" "maketest" { + application_schema = jsonencode( + { + properties = { + key = { + properties = { + authenticated_vlan = { + type = "string" + } + authorization_status = { + type = "string" + } + fallback_vlan_active = { + enum = [ + "True", + "False", + ] + type = "string" + } + port_status = { + enum = [ + "authorized", + "blocked", + ] + type = "string" + } + supplicant_mac = { + pattern = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" + type = "string" + } + } + required = [ + "supplicant_mac", + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active", + ] + type = "object" + } + value = { + description = "0 in case of blocked, 1 in case of authorized" + type = "integer" + } + } + required = [ + "key", + "value", + ] + type = "object" + } + ) + description = "Test Telemetry Service B" + service_name = "TestTelemetryServiceC" + storage_schema_path = "aos.sdk.telemetry.schemas.iba_integer_data" +} + +output "r" { + value = apstra_telemetry_service_registry_entry.maketest +} + +#Output looks something like this +#Outputs: +# +#r = { +#"application_schema" = "{\"properties\":{\"key\":{\"properties\":{\"authenticated_vlan\":{\"type\":\"string\"},\"authorization_status\":{\"type\":\"string\"},\"fallback_vlan_active\":{\"enum\":[\"True\",\"False\"],\"type\":\"string\"},\"port_status\":{\"enum\":[\"authorized\",\"blocked\"],\"type\":\"string\"},\"supplicant_mac\":{\"pattern\":\"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\",\"type\":\"string\"}},\"required\":[\"supplicant_mac\",\"authenticated_vlan\",\"authorization_status\",\"port_status\",\"fallback_vlan_active\"],\"type\":\"object\"},\"value\":{\"description\":\"0 in case of blocked, 1 in case of authorized\",\"type\":\"integer\"}},\"required\":[\"key\",\"value\"],\"type\":\"object\"}" +#"built_in" = false +#"description" = "Test Telemetry Service B" +#"service_name" = "TestTelemetryServiceC" +#"storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +#"version" = "" +#} +``` + + +## Schema + +### Required + +- `application_schema` (String) Application Schema expressed in Json schema +- `service_name` (String) Service Name. Used to identify the Service. +- `storage_schema_path` (String) Storage Schema Path + +### Optional + +- `description` (String) Description +- `version` (String) Version + +### Read-Only + +- `built_in` (Boolean) True If built in. + + + diff --git a/examples/data-sources/apstra_telemetry_service_registry_entries/example.tf b/examples/data-sources/apstra_telemetry_service_registry_entries/example.tf new file mode 100644 index 00000000..e9ad1197 --- /dev/null +++ b/examples/data-sources/apstra_telemetry_service_registry_entries/example.tf @@ -0,0 +1,119 @@ + +# The following example shows getting a list of +# Apstra Telemetry Service Registy Entries + +# Get all Entries +data "apstra_telemetry_service_registry_entries" "all" { +} +output "all_entries"{ + value = data.apstra_telemetry_service_registry_entries.all +} + +#Get only built-in Entries +data "apstra_telemetry_service_registry_entries" "builtin" { + built_in = true +} +output "builtin_entries"{ + value = data.apstra_telemetry_service_registry_entries.builtin +} + +#Get Only non-built-in Entries +data "apstra_telemetry_service_registry_entries" "not_builtin" { + built_in = false +} +output "not_builtin_entries"{ + value = data.apstra_telemetry_service_registry_entries.not_builtin +} + +#Output will look something like this +#Outputs: +# +#all_entries = { +#"built_in" = tobool(null) +#"service_names" = toset([ +#"TestTelemetryServiceA", +#"TestTelemetryServiceC", +#"arp", +#"bgp", +#"bgp_communities", +#"bgp_route", +#"blueprint_collector", +#"disk_util", +#"dot1x", +#"dot1x_hosts", +#"environment", +#"evpn_host_flap", +#"evpn_host_flap_count", +#"evpn_vxlan_type1", +#"evpn_vxlan_type3", +#"evpn_vxlan_type4", +#"evpn_vxlan_type5", +#"hostname", +#"interface", +#"interface_counters", +#"lag", +#"lldp", +#"mac", +#"mlag", +#"multiagent_detector", +#"nsxt", +#"optical_xcvr", +#"ospf_state", +#"poe_controller", +#"poe_interfaces", +#"resource_util", +#"route", +#"route_lookup", +#"shared_tunnel_mode", +#"virtual_infra", +#"vxlan_floodlist", +#"xcvr", +#]) +#} +#builtin_entries = { +#"built_in" = true +#"service_names" = toset([ +#"arp", +#"bgp", +#"bgp_communities", +#"bgp_route", +#"blueprint_collector", +#"disk_util", +#"dot1x", +#"dot1x_hosts", +#"environment", +#"evpn_host_flap", +#"evpn_host_flap_count", +#"evpn_vxlan_type1", +#"evpn_vxlan_type3", +#"evpn_vxlan_type4", +#"evpn_vxlan_type5", +#"hostname", +#"interface", +#"interface_counters", +#"lag", +#"lldp", +#"mac", +#"mlag", +#"multiagent_detector", +#"nsxt", +#"optical_xcvr", +#"ospf_state", +#"poe_controller", +#"poe_interfaces", +#"resource_util", +#"route", +#"route_lookup", +#"shared_tunnel_mode", +#"virtual_infra", +#"vxlan_floodlist", +#"xcvr", +#]) +#} +#not_builtin_entries = { +#"built_in" = false +#"service_names" = toset([ +#"TestTelemetryServiceA", +#"TestTelemetryServiceC", +#]) +#} diff --git a/examples/data-sources/apstra_telemetry_service_registry_entry/example.tf b/examples/data-sources/apstra_telemetry_service_registry_entry/example.tf new file mode 100644 index 00000000..37037b37 --- /dev/null +++ b/examples/data-sources/apstra_telemetry_service_registry_entry/example.tf @@ -0,0 +1,38 @@ + +# The following example shows getting a list of +# Apstra Telemetry Service Registy Entries + +#Get Only non-built-in Entries +data "apstra_telemetry_service_registry_entries" "not_builtin" { + built_in = false +} + +data "apstra_telemetry_service_registry_entry" "all_not_built_in" { + for_each = data.apstra_telemetry_service_registry_entries.not_builtin.service_names + service_name = each.value +} + +output "not_built_in_emtry" { + value = data.apstra_telemetry_service_registry_entry.all_not_built_in +} + +#Output looks something like this. +#Outputs +#not_built_in_emtry = { +# "TestTelemetryServiceA" = { +# "application_schema" = "{\"properties\": {\"key\": {\"properties\": {\"authenticated_vlan\": {\"type\": \"string\"}, \"authorization_status\": {\"type\": \"string\"}, \"fallback_vlan_active\": {\"enum\": [\"True\", \"False\"], \"type\": \"string\"}, \"port_status\": {\"enum\": [\"authorized\", \"blocked\"], \"type\": \"string\"}, \"supplicant_mac\": {\"pattern\": \"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\", \"type\": \"string\"}}, \"required\": [\"supplicant_mac\", \"authenticated_vlan\", \"authorization_status\", \"port_status\", \"fallback_vlan_active\"], \"type\": \"object\"}, \"value\": {\"description\": \"0 in case of blocked, 1 in case of authorized\", \"type\": \"integer\"}}, \"required\": [\"key\", \"value\"], \"type\": \"object\"}" +# "built_in" = false +# "description" = "Test Telemetry Service A" +# "service_name" = "TestTelemetryServiceA" +# "storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +# "version" = "" +# } +# "TestTelemetryServiceC" = { +# "application_schema" = "{\"properties\": {\"key\": {\"properties\": {\"authenticated_vlan\": {\"type\": \"string\"}, \"authorization_status\": {\"type\": \"string\"}, \"fallback_vlan_active\": {\"enum\": [\"True\", \"False\"], \"type\": \"string\"}, \"port_status\": {\"enum\": [\"authorized\", \"blocked\"], \"type\": \"string\"}, \"supplicant_mac\": {\"pattern\": \"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\", \"type\": \"string\"}}, \"required\": [\"supplicant_mac\", \"authenticated_vlan\", \"authorization_status\", \"port_status\", \"fallback_vlan_active\"], \"type\": \"object\"}, \"value\": {\"description\": \"0 in case of blocked, 1 in case of authorized\", \"type\": \"integer\"}}, \"required\": [\"key\", \"value\"], \"type\": \"object\"}" +# "built_in" = false +# "description" = "Test Telemetry Service B" +# "service_name" = "TestTelemetryServiceC" +# "storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +# "version" = "" +# } +#} diff --git a/examples/resources/apstra_telemetry_service_registry_entry/example.tf b/examples/resources/apstra_telemetry_service_registry_entry/example.tf new file mode 100644 index 00000000..8bc49ada --- /dev/null +++ b/examples/resources/apstra_telemetry_service_registry_entry/example.tf @@ -0,0 +1,72 @@ +resource "apstra_telemetry_service_registry_entry" "maketest" { + application_schema = jsonencode( + { + properties = { + key = { + properties = { + authenticated_vlan = { + type = "string" + } + authorization_status = { + type = "string" + } + fallback_vlan_active = { + enum = [ + "True", + "False", + ] + type = "string" + } + port_status = { + enum = [ + "authorized", + "blocked", + ] + type = "string" + } + supplicant_mac = { + pattern = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" + type = "string" + } + } + required = [ + "supplicant_mac", + "authenticated_vlan", + "authorization_status", + "port_status", + "fallback_vlan_active", + ] + type = "object" + } + value = { + description = "0 in case of blocked, 1 in case of authorized" + type = "integer" + } + } + required = [ + "key", + "value", + ] + type = "object" + } + ) + description = "Test Telemetry Service B" + service_name = "TestTelemetryServiceC" + storage_schema_path = "aos.sdk.telemetry.schemas.iba_integer_data" +} + +output "r" { + value = apstra_telemetry_service_registry_entry.maketest +} + +#Output looks something like this +#Outputs: +# +#r = { +#"application_schema" = "{\"properties\":{\"key\":{\"properties\":{\"authenticated_vlan\":{\"type\":\"string\"},\"authorization_status\":{\"type\":\"string\"},\"fallback_vlan_active\":{\"enum\":[\"True\",\"False\"],\"type\":\"string\"},\"port_status\":{\"enum\":[\"authorized\",\"blocked\"],\"type\":\"string\"},\"supplicant_mac\":{\"pattern\":\"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$\",\"type\":\"string\"}},\"required\":[\"supplicant_mac\",\"authenticated_vlan\",\"authorization_status\",\"port_status\",\"fallback_vlan_active\"],\"type\":\"object\"},\"value\":{\"description\":\"0 in case of blocked, 1 in case of authorized\",\"type\":\"integer\"}},\"required\":[\"key\",\"value\"],\"type\":\"object\"}" +#"built_in" = false +#"description" = "Test Telemetry Service B" +#"service_name" = "TestTelemetryServiceC" +#"storage_schema_path" = "aos.sdk.telemetry.schemas.iba_integer_data" +#"version" = "" +#} From ea481720f151555222c114d584469e6e09228f85 Mon Sep 17 00:00:00 2001 From: Rajagopalan Subrahmanian Date: Thu, 11 Jul 2024 03:51:38 -0400 Subject: [PATCH 2/4] add the error check --- apstra/test_utils/telemetry_service_registry_entry.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apstra/test_utils/telemetry_service_registry_entry.go b/apstra/test_utils/telemetry_service_registry_entry.go index f9498377..4580e1e8 100644 --- a/apstra/test_utils/telemetry_service_registry_entry.go +++ b/apstra/test_utils/telemetry_service_registry_entry.go @@ -66,6 +66,8 @@ func TelemetryServiceRegistryEntryA(t testing.TB, ctx context.Context) *apstra.T Version: "", } ts, err := client.GetTelemetryServiceRegistryEntry(ctx, "TestTelemetryServiceA") + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, client.DeleteTelemetryServiceRegistryEntry(ctx, sn)) }) if ts != nil { return ts } From b03c34f45c35a9c96bfe09b60db4db54566a7b76 Mon Sep 17 00:00:00 2001 From: Rajagopalan Subrahmanian Date: Thu, 11 Jul 2024 03:56:40 -0400 Subject: [PATCH 3/4] add the error check --- apstra/test_utils/telemetry_service_registry_entry.go | 1 - 1 file changed, 1 deletion(-) diff --git a/apstra/test_utils/telemetry_service_registry_entry.go b/apstra/test_utils/telemetry_service_registry_entry.go index 4580e1e8..ab9b0aab 100644 --- a/apstra/test_utils/telemetry_service_registry_entry.go +++ b/apstra/test_utils/telemetry_service_registry_entry.go @@ -67,7 +67,6 @@ func TelemetryServiceRegistryEntryA(t testing.TB, ctx context.Context) *apstra.T } ts, err := client.GetTelemetryServiceRegistryEntry(ctx, "TestTelemetryServiceA") require.NoError(t, err) - t.Cleanup(func() { require.NoError(t, client.DeleteTelemetryServiceRegistryEntry(ctx, sn)) }) if ts != nil { return ts } From de1b74bccd390f106d02aebcff86a3af9da0217b Mon Sep 17 00:00:00 2001 From: Chris Marget Date: Thu, 11 Jul 2024 21:36:07 -0400 Subject: [PATCH 4/4] update MarkdownDescription --- apstra/design/property_set.go | 4 ++-- docs/resources/property_set.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apstra/design/property_set.go b/apstra/design/property_set.go index c5da20ee..d0eeefd7 100644 --- a/apstra/design/property_set.go +++ b/apstra/design/property_set.go @@ -64,14 +64,14 @@ func (o PropertySet) DataSourceAttributes() map[string]dataSourceSchema.Attribut func (o PropertySet) ResourceAttributes() map[string]resourceSchema.Attribute { return map[string]resourceSchema.Attribute{ "id": resourceSchema.StringAttribute{ - MarkdownDescription: "Populate this field to look up a Property Set by ID. Required when `name` is omitted.", + MarkdownDescription: "Apstra ID number of the Property Set.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "name": resourceSchema.StringAttribute{ - MarkdownDescription: "Populate this field to look up a Property Set by name. Required when `id` is omitted.", + MarkdownDescription: "Name of the Property Set.", Required: true, Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, }, diff --git a/docs/resources/property_set.md b/docs/resources/property_set.md index e9c1a9fc..2de517c0 100644 --- a/docs/resources/property_set.md +++ b/docs/resources/property_set.md @@ -41,12 +41,12 @@ resource "apstra_property_set" "r" { ### Required - `data` (String) A map of values in the Property Set in JSON format -- `name` (String) Populate this field to look up a Property Set by name. Required when `id` is omitted. +- `name` (String) Name of the Property Set. ### Read-Only - `blueprints` (Set of String) Set of blueprints that this Property Set might be associated with. -- `id` (String) Populate this field to look up a Property Set by ID. Required when `name` is omitted. +- `id` (String) Apstra ID number of the Property Set. - `keys` (Set of String) Set of keys defined in the Property Set.