diff --git a/Justfile b/Justfile index a80c8035..37113c6b 100644 --- a/Justfile +++ b/Justfile @@ -87,10 +87,10 @@ fmt: clean: find . -name ".coverage*" -type f -delete -plan: +plan +ARGS='': cd {{ CONFIG_API_PROVIDER_DIR }} && go install . - cd {{ CONFIG_API_PROVIDER_DIR }}/examples/full-demo && terraform plan + cd {{ CONFIG_API_PROVIDER_DIR }}/examples/full-demo && terraform plan -var client_secret=secret {{ ARGS }} -apply: +apply +ARGS='': cd {{ CONFIG_API_PROVIDER_DIR }} && go install . - cd {{ CONFIG_API_PROVIDER_DIR }}/examples/full-demo && terraform apply + cd {{ CONFIG_API_PROVIDER_DIR }}/examples/full-demo && terraform apply -var client_secret=secret {{ ARGS }} diff --git a/pkg/config-api-provider/examples/full-demo/main.tf b/pkg/config-api-provider/examples/full-demo/main.tf index 5ae882f1..d9b4696f 100644 --- a/pkg/config-api-provider/examples/full-demo/main.tf +++ b/pkg/config-api-provider/examples/full-demo/main.tf @@ -6,7 +6,12 @@ terraform { } } -provider "uxi" {} +provider "uxi" { + host = "test.api.capenetworks.com" + client_id = "client_id" + client_secret = "some_random_secret" + token_url = "https://test.sso.common.cloud.hpe.com/as/token.oauth2" +} data "uxi_root_group" "my_root_group" {} diff --git a/pkg/config-api-provider/go.mod b/pkg/config-api-provider/go.mod index d4d44603..b6fd5005 100644 --- a/pkg/config-api-provider/go.mod +++ b/pkg/config-api-provider/go.mod @@ -6,10 +6,11 @@ toolchain go1.22.5 require ( github.com/aruba-uxi/configuration-api-terraform-provider/pkg/config-api-client v0.0.0-00010101000000-000000000000 + github.com/h2non/gock v1.2.0 github.com/hashicorp/terraform-plugin-framework v1.9.0 github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-testing v1.10.0 - github.com/stretchr/testify v1.9.0 + golang.org/x/oauth2 v0.17.0 ) require ( @@ -17,10 +18,10 @@ require ( github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -49,8 +50,6 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.5.2 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -66,7 +65,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.34.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/aruba-uxi/configuration-api-terraform-provider/pkg/config-api-client => ../config-api-client diff --git a/pkg/config-api-provider/go.sum b/pkg/config-api-provider/go.sum index 4a663b0a..095e2aeb 100644 --- a/pkg/config-api-provider/go.sum +++ b/pkg/config-api-provider/go.sum @@ -42,6 +42,10 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= +github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= @@ -120,6 +124,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= @@ -131,8 +137,6 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -163,6 +167,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/config-api-provider/provider/provider.go b/pkg/config-api-provider/provider/provider.go index 5576b065..32e0647a 100644 --- a/pkg/config-api-provider/provider/provider.go +++ b/pkg/config-api-provider/provider/provider.go @@ -2,13 +2,22 @@ package provider import ( "context" + "os" datasources "github.com/aruba-uxi/configuration-api-terraform-provider/pkg/terraform-provider-configuration/provider/data-sources" "github.com/aruba-uxi/configuration-api-terraform-provider/pkg/terraform-provider-configuration/provider/resources" "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" + + "github.com/aruba-uxi/configuration-api-terraform-provider/pkg/config-api-client" + "github.com/hashicorp/terraform-plugin-framework/types" + "net/http" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/clientcredentials" ) // Ensure the implementation satisfies the expected interfaces. @@ -16,6 +25,8 @@ var ( _ provider.Provider = &uxiConfigurationProvider{} ) +const tokenURLDefault = "https://sso.common.cloud.hpe.com/as/token.oauth2" + // New is a helper function to simplify provider server and testing implementation. func New(version string) func() provider.Provider { return func() provider.Provider { @@ -25,6 +36,14 @@ func New(version string) func() provider.Provider { } } +// maps provider schema data to a Go type. +type uxiProviderModel struct { + Host types.String `tfsdk:"host"` + ClientID types.String `tfsdk:"client_id"` + ClientSecret types.String `tfsdk:"client_secret"` + TokenURL types.String `tfsdk:"token_url"` +} + type uxiConfigurationProvider struct { // version is set to the provider version on release, "dev" when the // provider is built and ran locally, and "test" when running acceptance @@ -40,14 +59,97 @@ func (p *uxiConfigurationProvider) Metadata(_ context.Context, _ provider.Metada // Schema defines the provider-level schema for configuration data. func (p *uxiConfigurationProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { - resp.Schema = schema.Schema{} + resp.Schema = schema.Schema{Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{Optional: true}, + "client_id": schema.StringAttribute{Optional: true}, + "client_secret": schema.StringAttribute{Optional: true, Sensitive: true}, + "token_url": schema.StringAttribute{Optional: true}, + }} } // TODO: Obtain a greenlake access token // Configure prepares a Configuration API client for data sources and resources. func (p *uxiConfigurationProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { // Init + var config uxiProviderModel + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + host := os.Getenv("UXI_HOST") + clientID := os.Getenv("CLIENT_ID") + clientSecret := os.Getenv("CLIENT_SECRET") + tokenURL := os.Getenv("TOKEN_URL") + + if !config.Host.IsNull() { + host = config.Host.ValueString() + } + + if !config.ClientID.IsNull() { + clientID = config.ClientID.ValueString() + } + + if !config.ClientSecret.IsNull() { + clientSecret = config.ClientSecret.ValueString() + } + + if !config.TokenURL.IsNull() { + tokenURL = config.TokenURL.ValueString() + } + + // If any of the expected configurations are missing, return + // errors with provider-specific guidance. + + if host == "" { + resp.Diagnostics.AddAttributeError( + path.Root("host"), + "Missing Host", + "The provider cannot initialize as there is a missing or empty value for the UXI API host. "+ + "Set the host value in the configuration or use the UXI_HOST environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if clientID == "" { + resp.Diagnostics.AddAttributeError( + path.Root("client_id"), + "Missing Client ID", + "The provider cannot initialize as there is a missing or empty value for the Client ID. "+ + "Set the Client ID value in the configuration or use the CLIENT_ID environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if clientSecret == "" { + resp.Diagnostics.AddAttributeError( + path.Root("client_secret"), + "Missing Client Secret", + "The provider cannot initialize as there is a missing or empty value for the Client Secret. "+ + "Set the Client Secret value in the configuration or use the CLIENT_SECRET environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if tokenURL == "" { + tokenURL = tokenURLDefault + } + + if resp.Diagnostics.HasError() { + return + } + // initialise client + uxiConfiguration := config_api_client.NewConfiguration() + uxiConfiguration.Host = host + uxiConfiguration.Scheme = "https" + uxiConfiguration.HTTPClient = getHttpClient(clientID, clientSecret, tokenURL) + uxiClient := config_api_client.NewAPIClient(uxiConfiguration) + + // Make the client available during DataSource and Resource type Configure methods. + resp.DataSourceData = uxiClient + resp.ResourceData = uxiClient } // DataSources defines the data sources implemented in the provider. @@ -72,3 +174,16 @@ func (p *uxiConfigurationProvider) Resources(_ context.Context) []func() resourc resources.NewServiceTestGroupAssignmentResource, } } + +func getHttpClient(clientID string, clientSecret string, tokenURL string) *http.Client { + // Set up the client credentials config + config := &clientcredentials.Config{ + ClientID: clientID, + ClientSecret: clientSecret, + TokenURL: tokenURL, + AuthStyle: oauth2.AuthStyleInParams, + } + + // Create a context and fetch a token + return config.Client(context.Background()) +} diff --git a/pkg/config-api-provider/provider/resources/group.go b/pkg/config-api-provider/provider/resources/group.go index c040cb20..82c122fe 100644 --- a/pkg/config-api-provider/provider/resources/group.go +++ b/pkg/config-api-provider/provider/resources/group.go @@ -3,6 +3,8 @@ package resources import ( "context" + "github.com/aruba-uxi/configuration-api-terraform-provider/pkg/config-api-client" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -24,10 +26,10 @@ type groupResourceModel struct { } type GroupResponseModel struct { - UID string - Name string - ParentUid *string - Path string + UID string `json:"uid"` + Name string `json:"name"` + ParentUid *string `json:"parent_uid"` + Path string `json:"path"` } type GroupCreateRequestModel struct { @@ -43,7 +45,9 @@ func NewGroupResource() resource.Resource { return &groupResource{} } -type groupResource struct{} +type groupResource struct { + client *config_api_client.APIClient +} func (r *groupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_group" @@ -73,6 +77,23 @@ func (r *groupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp } func (r *groupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Add a nil check when handling ProviderData because Terraform + // sets that data after it calls the ConfigureProvider RPC. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*config_api_client.APIClient) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + "Resource type: Group. Please report this issue to the provider developers.", + ) + return + } + + r.client = client } func (r *groupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { @@ -84,17 +105,20 @@ func (r *groupResource) Create(ctx context.Context, req resource.CreateRequest, return } - // TODO: Call client create-group method - // We are mocking the response of the client for this early stage of development - group := CreateGroup(GroupCreateRequestModel{ - Name: plan.Name.ValueString(), - ParentUid: plan.ParentGroupId.ValueString(), - }) + groups_post_request := config_api_client.NewGroupsPostRequest(plan.ParentGroupId.ValueString(), plan.Name.ValueString()) + group, _, err := r.client.ConfigurationAPI.GroupsPostConfigurationAppV1GroupsPost(context.Background()).GroupsPostRequest(*groups_post_request).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error creating group", + "Could not create group, unexpected error: "+err.Error(), + ) + return + } // Update the state to match the plan (replace with response from client) - plan.ID = types.StringValue(group.UID) + plan.ID = types.StringValue(group.Uid) plan.Name = types.StringValue(group.Name) - plan.ParentGroupId = types.StringValue(*group.ParentUid) + plan.ParentGroupId = types.StringValue(group.ParentUid) // Set state to fully populated data diags = resp.State.Set(ctx, plan) @@ -187,19 +211,6 @@ var GetGroup = func(uid string) GroupResponseModel { } } -var CreateGroup = func(request GroupCreateRequestModel) GroupResponseModel { - // TODO: Query the group using the client - - parent_uid := "mock_parent_uid" - - return GroupResponseModel{ - UID: "mock_uid", - Name: "mock_name", - ParentUid: &parent_uid, - Path: "mock_path", - } -} - var UpdateGroup = func(request GroupUpdateRequestModel) GroupResponseModel { // TODO: Query the group using the client diff --git a/pkg/config-api-provider/test/agent_group_assignment_test.go b/pkg/config-api-provider/test/agent_group_assignment_test.go index 8fc3f173..8e1f2351 100644 --- a/pkg/config-api-provider/test/agent_group_assignment_test.go +++ b/pkg/config-api-provider/test/agent_group_assignment_test.go @@ -15,15 +15,14 @@ func TestAgentGroupAssignmentResource(t *testing.T) { // Creating a agent group assignment { PreConfig: func() { + MockOAuth() // required for agent import resources.GetAgent = func(uid string) resources.AgentResponseModel { return GenerateAgentResponseModel(uid, "") } // required for group create - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid", "", "") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid", "", ""))) resources.GetGroup = func(uid string) resources.GroupResponseModel { return GenerateGroupResponseModel("group_uid", "", "") } @@ -74,6 +73,7 @@ func TestAgentGroupAssignmentResource(t *testing.T) { // Update and Read testing { PreConfig: func() { + MockOAuth() resources.GetAgent = func(uid string) resources.AgentResponseModel { if uid == "agent_uid" { return GenerateAgentResponseModel(uid, "") @@ -83,9 +83,7 @@ func TestAgentGroupAssignmentResource(t *testing.T) { } // required for creating another group - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid_2", "_2", "_2") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid_2", "_2", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "group_uid" { return GenerateGroupResponseModel(uid, "", "") diff --git a/pkg/config-api-provider/test/group_test.go b/pkg/config-api-provider/test/group_test.go index 032d27d9..544eccdd 100644 --- a/pkg/config-api-provider/test/group_test.go +++ b/pkg/config-api-provider/test/group_test.go @@ -20,9 +20,9 @@ func TestGroupResource(t *testing.T) { // Create and Read testing { PreConfig: func() { - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("uid", "", "") - } + MockOAuth() + MockPostGroup(StructToMap(GenerateGroupResponseModel("uid", "", ""))) + resources.GetGroup = func(uid string) resources.GroupResponseModel { return GenerateGroupResponseModel(uid, "", "") } @@ -69,9 +69,8 @@ func TestGroupResource(t *testing.T) { // Update that does trigger a recreate { PreConfig: func() { - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("new_uid", "", "_2") - } + MockOAuth() + MockPostGroup(StructToMap(GenerateGroupResponseModel("new_uid", "", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "uid" { return GenerateGroupResponseModel(uid, "", "") diff --git a/pkg/config-api-provider/test/network_group_assignment_test.go b/pkg/config-api-provider/test/network_group_assignment_test.go index 0f37cbdf..606f0eaa 100644 --- a/pkg/config-api-provider/test/network_group_assignment_test.go +++ b/pkg/config-api-provider/test/network_group_assignment_test.go @@ -16,15 +16,14 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { // Creating a network group assignment { PreConfig: func() { + MockOAuth() // required for network import resources.GetWiredNetwork = func(uid string) resources.WiredNetworkResponseModel { return GenerateWiredNetworkResponseModel(uid, "") } // required for group create - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid", "", "") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid", "", ""))) resources.GetGroup = func(uid string) resources.GroupResponseModel { return GenerateGroupResponseModel("group_uid", "", "") } @@ -72,6 +71,7 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { // Update and Read testing { PreConfig: func() { + MockOAuth() resources.GetWiredNetwork = func(uid string) resources.WiredNetworkResponseModel { if uid == "network_uid" { return GenerateWiredNetworkResponseModel(uid, "") @@ -81,9 +81,7 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { } // required for creating another group - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid_2", "_2", "_2") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid_2", "_2", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "group_uid" { return GenerateGroupResponseModel("uid", "", "") @@ -176,15 +174,14 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { // Creating a network group assignment { PreConfig: func() { + MockOAuth() // required for network import resources.GetWirelessNetwork = func(uid string) resources.WirelessNetworkResponseModel { return GenerateWirelessNetworkResponseModel(uid, "") } // required for group create - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid", "", "") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid", "", ""))) resources.GetGroup = func(uid string) resources.GroupResponseModel { return GenerateGroupResponseModel(uid, "", "") } @@ -232,6 +229,7 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { // Update and Read testing { PreConfig: func() { + MockOAuth() resources.GetWirelessNetwork = func(uid string) resources.WirelessNetworkResponseModel { if uid == "network_uid" { return GenerateWirelessNetworkResponseModel(uid, "") @@ -241,9 +239,7 @@ func TestNetworkGroupAssignmentResource(t *testing.T) { } // required for creating another group - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid_2", "_2", "_2") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid_2", "_2", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "group_uid" { return GenerateGroupResponseModel(uid, "", "") diff --git a/pkg/config-api-provider/test/provider_test.go b/pkg/config-api-provider/test/provider_test.go index a181751e..59710ad6 100644 --- a/pkg/config-api-provider/test/provider_test.go +++ b/pkg/config-api-provider/test/provider_test.go @@ -7,7 +7,12 @@ import ( ) const ( - providerConfig = `provider "uxi" {}` + providerConfig = `provider "uxi" { + host = "test.api.capenetworks.com" + client_id = "client_id" + client_secret = "client_secret" + token_url = "https://test.sso.common.cloud.hpe.com/as/token.oauth2" + }` ) var ( diff --git a/pkg/config-api-provider/test/sensor_group_assignment_test.go b/pkg/config-api-provider/test/sensor_group_assignment_test.go index 06f90b5d..7a21d6c2 100644 --- a/pkg/config-api-provider/test/sensor_group_assignment_test.go +++ b/pkg/config-api-provider/test/sensor_group_assignment_test.go @@ -15,18 +15,16 @@ func TestSensorGroupAssignmentResource(t *testing.T) { // Creating a sensor group assignment { PreConfig: func() { + MockOAuth() // required for sensor import resources.GetSensor = func(uid string) resources.SensorResponseModel { return GenerateSensorResponseModel(uid, "") } // required for group create - groupResponse := GenerateGroupResponseModel("group_uid", "", "") - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return groupResponse - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid", "", ""))) resources.GetGroup = func(uid string) resources.GroupResponseModel { - return groupResponse + return GenerateGroupResponseModel("group_uid", "", "") } // required for sensor group assignment create @@ -76,6 +74,7 @@ func TestSensorGroupAssignmentResource(t *testing.T) { // Update and Read testing { PreConfig: func() { + MockOAuth() resources.GetSensor = func(uid string) resources.SensorResponseModel { if uid == "sensor_uid" { return GenerateSensorResponseModel("sensor_uid", "") @@ -85,15 +84,12 @@ func TestSensorGroupAssignmentResource(t *testing.T) { } // required for creating another group - newGroupResponse := GenerateGroupResponseModel("group_uid_2", "_2", "_2") - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return newGroupResponse - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid_2", "_2", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "group_uid" { return GenerateGroupResponseModel(uid, "", "") } else { - return newGroupResponse + return GenerateGroupResponseModel("group_uid_2", "_2", "_2") } } diff --git a/pkg/config-api-provider/test/service_test_group_assignment_test.go b/pkg/config-api-provider/test/service_test_group_assignment_test.go index 57c476ef..abf1d9b3 100644 --- a/pkg/config-api-provider/test/service_test_group_assignment_test.go +++ b/pkg/config-api-provider/test/service_test_group_assignment_test.go @@ -15,18 +15,16 @@ func TestServiceTestGroupAssignmentResource(t *testing.T) { // Creating a serviceTest group assignment { PreConfig: func() { + MockOAuth() // required for serviceTest import resources.GetServiceTest = func(uid string) resources.ServiceTestResponseModel { return GenerateServiceTestResponseModel(uid, "") } // required for group create - groupResponse := GenerateGroupResponseModel("group_uid", "", "") - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return groupResponse - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid", "", ""))) resources.GetGroup = func(uid string) resources.GroupResponseModel { - return groupResponse + return GenerateGroupResponseModel("group_uid", "", "") } // required for serviceTest group assignment create @@ -73,6 +71,7 @@ func TestServiceTestGroupAssignmentResource(t *testing.T) { // Update and Read testing { PreConfig: func() { + MockOAuth() resources.GetServiceTest = func(uid string) resources.ServiceTestResponseModel { if uid == "service_test_uid" { return GenerateServiceTestResponseModel("service_test_uid", "") @@ -82,9 +81,7 @@ func TestServiceTestGroupAssignmentResource(t *testing.T) { } // required for creating another group - resources.CreateGroup = func(request resources.GroupCreateRequestModel) resources.GroupResponseModel { - return GenerateGroupResponseModel("group_uid_2", "_2", "_2") - } + MockPostGroup(StructToMap(GenerateGroupResponseModel("group_uid_2", "_2", "_2"))) resources.GetGroup = func(uid string) resources.GroupResponseModel { if uid == "group_uid" { return GenerateGroupResponseModel(uid, "", "") diff --git a/pkg/config-api-provider/test/utils.go b/pkg/config-api-provider/test/utils.go index 73e36fe4..b74b0af2 100644 --- a/pkg/config-api-provider/test/utils.go +++ b/pkg/config-api-provider/test/utils.go @@ -1,7 +1,10 @@ package test import ( + "encoding/json" + "github.com/aruba-uxi/configuration-api-terraform-provider/pkg/terraform-provider-configuration/provider/resources" + "github.com/h2non/gock" ) func GenerateSensorResponseModel(uid string, postfix string) resources.SensorResponseModel { @@ -128,3 +131,35 @@ func GenerateServiceTestGroupAssignmentResponse(uid string, postfix string) reso ServiceTestUID: "service_test_uid" + postfix, } } + +// Converts a struct to a map while maintaining the json alias as keys +func StructToMap(obj interface{}) map[string]interface{} { + data, _ := json.Marshal(obj) // Convert to a json string + + newMap := map[string]interface{}{} + + _ = json.Unmarshal(data, &newMap) // Convert to a map + return newMap +} + +func MockOAuth() { + gock.New("https://test.sso.common.cloud.hpe.com"). + Post("/as/token.oauth2"). + MatchHeader("Content-Type", "application/x-www-form-urlencoded"). + Reply(200). + JSON(map[string]interface{}{ + "access_token": "mock_token", + "token_type": "bearer", + "expires_in": 3600, + }) +} + +func MockPostGroup(response map[string]interface{}) { + gock.New("https://test.api.capenetworks.com"). + Post("/configuration/app/v1/groups"). + MatchHeader("Content-Type", "application/json"). + MatchHeader("Authorization", "mock_token"). + Reply(200). + JSON(response) + +}