From 7242ece278a5474eb0bf778180a62a780a012be4 Mon Sep 17 00:00:00 2001 From: Bogdan Guranda Date: Wed, 8 May 2024 14:58:33 +0300 Subject: [PATCH] Run acceptance tests only when 'acceptance' go:build tag is present --- Makefile | 2 +- docs/data-sources/type.md | 11 ++++ docs/index.md | 41 +++++++++++- docs/resources/object.md | 21 ++++++- ...source.go => datasource_knowledge_type.go} | 24 +++---- ... => datasource_knowledge_type_acc_test.go} | 6 +- internal/provider/provider.go | 4 +- ...{provider_test.go => provider_acc_test.go} | 4 +- ...source.go => resource_knowledge_object.go} | 63 ++++++++++++------- ... => resource_knowledge_object_acc_test.go} | 18 +++--- 10 files changed, 144 insertions(+), 50 deletions(-) rename internal/provider/{type_data_source.go => datasource_knowledge_type.go} (75%) rename internal/provider/{type_data_source_test.go => datasource_knowledge_type_acc_test.go} (92%) rename internal/provider/{provider_test.go => provider_acc_test.go} (92%) rename internal/provider/{object_resource.go => resource_knowledge_object.go} (77%) rename internal/provider/{object_resource_test.go => resource_knowledge_object_acc_test.go} (93%) diff --git a/Makefile b/Makefile index eb39824..e848246 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ lint-fix: $(GOLANGCI_LINT) .PHONY: test test: - TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m + go test ./... -v $(TESTARGS) -timeout 120m .PHONY: plugin plugin: diff --git a/docs/data-sources/type.md b/docs/data-sources/type.md index 6666788..6f62ad0 100644 --- a/docs/data-sources/type.md +++ b/docs/data-sources/type.md @@ -10,7 +10,18 @@ description: |- Type data source +Enables you to read any type of Cisco Observability Platform. Types are just schemas for the objects. +Type name is the field required to get the type data source. +## Example usage + +In this example we want to fetch a type called fmm:namespace. + +```terraform +data "observability_type" "ns" { + type_name = "fmm:namespace" +} +``` ## Schema diff --git a/docs/index.md b/docs/index.md index 2a12fb3..a22cfcb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,11 +6,50 @@ description: |- --- -# observability Provider +# Observability Provider +Terraform Observability provider enables users to provision objects as resources and read types as data sources +## Authentication +To start using the Observability Terraform Provider you need to authenticate with the Cisco Observability Platform. +You can do this by either using service-principal or oauth as an authentication method: + + +```terraform +terraform { + required_providers { + observability = { + source = "registry.terraform.io/cisco-open/observability" + } + } +} + +provider "observability" { + tenant = "" + auth_method = "service-principal" + url = "https://" + secrets_file = "" +} + +``` + +```terraform +terraform { + required_providers { + observability = { + source = "registry.terraform.io/cisco-open/observability" + } + } +} + +provider "observability" { + tenant = "" + auth_method = "oauth" + url = "https://" +} +``` ## Schema diff --git a/docs/resources/object.md b/docs/resources/object.md index 92616c0..e1f399d 100644 --- a/docs/resources/object.md +++ b/docs/resources/object.md @@ -10,7 +10,26 @@ description: |- Object resource - +Enables you to create and manage any object of Cisco Observability Platform. Objects are actual populated values of a type. Data is a field which acts like a container for any object payload. + +## Example usage + +```terraform +resource "observability_object" "conn" { + type_name = "" + object_id = "" + layer_type = "TENANT" + layer_id = "" + import_id = "||TENANT|" + data = jsonencode( + { + "field1" : "value1", + "field2" : "value2", + ... + } + ) +} +``` ## Schema diff --git a/internal/provider/type_data_source.go b/internal/provider/datasource_knowledge_type.go similarity index 75% rename from internal/provider/type_data_source.go rename to internal/provider/datasource_knowledge_type.go index 1036b0a..dc49920 100644 --- a/internal/provider/type_data_source.go +++ b/internal/provider/datasource_knowledge_type.go @@ -16,30 +16,30 @@ import ( ) // Ensure provider defined types fully satisfy framework interfaces. -var _ datasource.DataSource = &TypeDataSource{} +var _ datasource.DataSource = &KnowledgeTypeDataSource{} -func NewTypeDataSource() datasource.DataSource { - return &TypeDataSource{} +func NewKnowledgeTypeDataSource() datasource.DataSource { + return &KnowledgeTypeDataSource{} } -// TypeDataSource defines the data source implementation. -type TypeDataSource struct { +// KnowledgeTypeDataSource defines the data source implementation. +type KnowledgeTypeDataSource struct { client *api.AppdClient } -// TypeDataSourceModel describes the data source data model. -type TypeDataSourceModel struct { +// KnowledgeTypeDataSourceModel describes the data source data model. +type KnowledgeTypeDataSourceModel struct { Typename types.String `tfsdk:"type_name"` Data types.Dynamic `tfsdk:"data"` ID types.String `tfsdk:"id"` } -func (d *TypeDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { +func (d *KnowledgeTypeDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_type" } // Schema defines the schema for the data source. -func (d *TypeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { +func (d *KnowledgeTypeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ // This description is used by the documentation generator and the language server. MarkdownDescription: "Type data source", @@ -61,7 +61,7 @@ func (d *TypeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, r } } -func (d *TypeDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (d *KnowledgeTypeDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -80,8 +80,8 @@ func (d *TypeDataSource) Configure(_ context.Context, req datasource.ConfigureRe } //nolint:gocritic // Terraform framework requires the method signature to be as is -func (d *TypeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data TypeDataSourceModel +func (d *KnowledgeTypeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data KnowledgeTypeDataSourceModel // Read Terraform configuration data into the model resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) diff --git a/internal/provider/type_data_source_test.go b/internal/provider/datasource_knowledge_type_acc_test.go similarity index 92% rename from internal/provider/type_data_source_test.go rename to internal/provider/datasource_knowledge_type_acc_test.go index 8d00e3b..036b66c 100644 --- a/internal/provider/type_data_source_test.go +++ b/internal/provider/datasource_knowledge_type_acc_test.go @@ -4,16 +4,20 @@ // // SPDX-License-Identifier: MPL-2.0 +//go:build acceptance + package provider import ( + "fmt" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) //lint:ignore U1000 Ignore unused function temporarily for debugging -func _TestAccTypeDataSource(t *testing.T) { +func TestAccKnowledgeTypeDataSource(t *testing.T) { + fmt.Print("DNSAJDANSJDANSJDNAJSDNJASDNJANJSNDJASNDJA") resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 16c1114..308b582 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -266,13 +266,13 @@ func (p *COPProvider) Configure(ctx context.Context, req provider.ConfigureReque func (p *COPProvider) Resources(_ context.Context) []func() resource.Resource { return []func() resource.Resource{ - NewObjectResource, + NewKnowledgeObjectResource, } } func (p *COPProvider) DataSources(_ context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ - NewTypeDataSource, + NewKnowledgeTypeDataSource, } } diff --git a/internal/provider/provider_test.go b/internal/provider/provider_acc_test.go similarity index 92% rename from internal/provider/provider_test.go rename to internal/provider/provider_acc_test.go index b638b0e..0277229 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_acc_test.go @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MPL-2.0 +//go:build acceptance + package provider import ( @@ -16,7 +18,7 @@ const ( terraform { required_providers { observability = { - source = "testTerraform.com/appd/observability" + source = "registry.terraform.io/cisco-open/observability", } } } diff --git a/internal/provider/object_resource.go b/internal/provider/resource_knowledge_object.go similarity index 77% rename from internal/provider/object_resource.go rename to internal/provider/resource_knowledge_object.go index 72dcb43..a058124 100644 --- a/internal/provider/object_resource.go +++ b/internal/provider/resource_knowledge_object.go @@ -20,20 +20,20 @@ import ( ) // Ensure provider defined types fully satisfy framework interfaces. -var _ resource.Resource = &ObjectResource{} -var _ resource.ResourceWithImportState = &ObjectResource{} +var _ resource.Resource = &KnowledgeObjectResource{} +var _ resource.ResourceWithImportState = &KnowledgeObjectResource{} -func NewObjectResource() resource.Resource { - return &ObjectResource{} +func NewKnowledgeObjectResource() resource.Resource { + return &KnowledgeObjectResource{} } -// ObjectResource defines the resource implementation. -type ObjectResource struct { +// KnowledgeObjectResource defines the resource implementation. +type KnowledgeObjectResource struct { client *api.AppdClient } -// ObjectResourceModel describes the resource data model. -type ObjectResourceModel struct { +// KnowledgeObjectResourceModel describes the resource data model. +type KnowledgeObjectResourceModel struct { TypeName types.String `tfsdk:"type_name"` ObjectID types.String `tfsdk:"object_id"` LayerID types.String `tfsdk:"layer_id"` @@ -43,12 +43,12 @@ type ObjectResourceModel struct { ID types.String `tfsdk:"id"` } -func (r *ObjectResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *KnowledgeObjectResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_object" } // Schema defines the schema for the resource. -func (r *ObjectResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *KnowledgeObjectResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ // This description is used by the documentation generator and the language server. MarkdownDescription: "Object resource", @@ -89,7 +89,7 @@ func (r *ObjectResource) Schema(_ context.Context, _ resource.SchemaRequest, res } } -func (r *ObjectResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *KnowledgeObjectResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -108,9 +108,9 @@ func (r *ObjectResource) Configure(_ context.Context, req resource.ConfigureRequ } //nolint:gocritic // Terraform framework requires the method signature to be as is -func (r *ObjectResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { +func (r *KnowledgeObjectResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { tflog.Debug(ctx, "Create method invoked") - var data ObjectResourceModel + var data KnowledgeObjectResourceModel // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -145,10 +145,10 @@ func (r *ObjectResource) Create(ctx context.Context, req resource.CreateRequest, resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -//nolint:gocritic // Terraform framework requires the method signature to be as is -func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +//nolint:gocritic,funlen // Terraform framework requires the method signature to be as is +func (r *KnowledgeObjectResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { tflog.Debug(ctx, "Read method invoked") - var data ObjectResourceModel + var data KnowledgeObjectResourceModel var importIDTokenLength = 4 // Read Terraform prior state data into the model @@ -179,6 +179,13 @@ func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, res layerID = identityFields[3] } + tflog.Debug(ctx, fmt.Sprintf("type name is %s", typeName)) + tflog.Debug(ctx, fmt.Sprintf("object id is %s", objID)) + tflog.Debug(ctx, fmt.Sprintf("layer ID is %s", layerID)) + tflog.Debug(ctx, fmt.Sprintf("layer type %s", layerType)) + tflog.Debug(ctx, fmt.Sprintf("data payload %s", currentDataPayload)) + tflog.Debug(ctx, fmt.Sprintf("import identifier is %s", importIdentifier)) + result, err := r.client.GetObject(typeName, objID, layerID, layerType) if err != nil { resp.Diagnostics.AddError( @@ -188,6 +195,7 @@ func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, res return } + tflog.Debug(ctx, fmt.Sprintf("api response is %s", string(result))) // update the model with the new values var parsedCurrentDataPayload map[string]any var parsedResponse map[string]any @@ -201,6 +209,7 @@ func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, res return } + tflog.Debug(ctx, fmt.Sprintf("parsed response into map is %v", parsedResponse)) if currentDataPayload != "" { err = json.Unmarshal([]byte(currentDataPayload), &parsedCurrentDataPayload) if err != nil { @@ -212,7 +221,17 @@ func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, res } } - dataPayload := parsedResponse["data"].(map[string]any) + // if we can't fetch any data from the cloud return + var dataPayload map[string]any + var ok bool + if dataPayload, ok = parsedResponse["data"].(map[string]any); !ok { + resp.Diagnostics.AddError( + fmt.Sprintf("Unable to assert data map from current object of type %s with id %s", typeName, objID), + err.Error(), + ) + return + } + if parsedCurrentDataPayload == nil { // data was not provided in this case, maybe import usecase // populate all the fields with what the observability api provided @@ -255,9 +274,9 @@ func (r *ObjectResource) Read(ctx context.Context, req resource.ReadRequest, res } //nolint:gocritic // Terraform framework requires the method signature to be as is -func (r *ObjectResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *KnowledgeObjectResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { tflog.Debug(ctx, "Update method invoked") - var data ObjectResourceModel + var data KnowledgeObjectResourceModel // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -290,9 +309,9 @@ func (r *ObjectResource) Update(ctx context.Context, req resource.UpdateRequest, } //nolint:gocritic // Terraform framework requires the method signature to be as is -func (r *ObjectResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *KnowledgeObjectResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { tflog.Debug(ctx, "Delete method invoked") - var data ObjectResourceModel + var data KnowledgeObjectResourceModel // Read Terraform prior state data into the model resp.Diagnostics.Append(req.State.Get(ctx, &data)...) @@ -317,6 +336,6 @@ func (r *ObjectResource) Delete(ctx context.Context, req resource.DeleteRequest, } } -func (r *ObjectResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *KnowledgeObjectResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("import_id"), req, resp) } diff --git a/internal/provider/object_resource_test.go b/internal/provider/resource_knowledge_object_acc_test.go similarity index 93% rename from internal/provider/object_resource_test.go rename to internal/provider/resource_knowledge_object_acc_test.go index 7091dfb..5c5e7e8 100644 --- a/internal/provider/object_resource_test.go +++ b/internal/provider/resource_knowledge_object_acc_test.go @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MPL-2.0 +//go:build acceptance + package provider import ( @@ -12,8 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) -//lint:ignore U1000 Ignore unused function temporarily for debugging -func _TestAccObjectResource(t *testing.T) { +func TestAccKnowledgeObjectResource(t *testing.T) { resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ @@ -59,13 +60,12 @@ resource "observability_object" "test" { ), }, // ImportState testing - // TO DO add this after the plugin is plublished - // { - // ResourceName: "observability_object.test", - // ImportState: true, - // ImportStateVerify: true, - // }, - // Update and Read testing + { + ResourceName: "observability_object.test", + ImportState: true, + ImportStateVerify: true, + ImportStateId: "anzen:cloudConnection|just-terraform-testing|TENANT|0eb4e853-34fb-4f77-b3fc-b9cd3b462366", + }, { Config: providerConfig + ` resource "observability_object" "test" {