Skip to content

Commit

Permalink
feat: tests and examples added for service accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
marnas committed Dec 3, 2024
1 parent ac6d8b5 commit aee2e28
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ jobs:
CDK_BASE_URL: http://localhost:8080
CDK_ADMIN_EMAIL: [email protected]
CDK_ADMIN_PASSWORD: testP4ss!
CDK_GATEWAY_BASE_URL: http://localhost:8888
CDK_GATEWAY_USER: admin
CDK_GATEWAY_PASSWORD: conduktor
TF_LOG_PROVIDER_CONDUKTOR: DEBUG
timeout-minutes: 15
run: |
Expand Down
6 changes: 5 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ services:
GATEWAY_HTTP_PORT: 8888
GATEWAY_PORT_START: 9094
GATEWAY_PORT_COUNT: 1
# OAuth config needed to test EXTERNAL service accounts
GATEWAY_SECURITY_PROTOCOL: SASL_PLAINTEXT
# GATEWAY_SECURITY_PROTOCOL: DELEGATED_SASL_PLAINTEXT
GATEWAY_LICENSE_KEY: ${CDK_LICENSE:-}
GATEWAY_OAUTH_JWKS_URL: "https://login.microsoftonline.com/common/discovery/keys"
GATEWAY_OAUTH_EXPECTED_ISSUER: "https://sts.windows.net/38755287-df00-48cd-805b-1ebe914e8b11/"
GATEWAY_OAUTH_EXPECTED_AUDIENCES: "[00000002-0000-0000-c000-000000000000]"

volumes:
pg_data: {}
Expand Down
2 changes: 1 addition & 1 deletion docs/resources/gateway_service_account_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ description: |-

Required:

- `type` (String) The type of the Service Accound. Can only be either LOCAL or EXTERNAL. Default value is LOCAL.
- `type` (String) The type of the Service Accound. Can only be either LOCAL or EXTERNAL.

Optional:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "conduktor_gateway_service_account_v2" "example" {
name = "complex-service-account"
# vcluster = "vcluster1"
spec {
type = "EXTERNAL"
external_names = ["externalName"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "conduktor_gateway_service_account_v2" "example" {
name = "simple-service-account"
spec {
type = "LOCAL"
}
}
2 changes: 1 addition & 1 deletion internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func (client *ConsoleClient) Delete(ctx context.Context, path string) error {
return nil
}

// This is a temporary workaround - will be revisited with the future client works
// This is a temporary workaround - will be revisited with the future client works.
func (client *GatewayClient) Apply(ctx context.Context, path string, resource interface{}) (ApplyResult, error) {
url := client.baseUrl + path
jsonData, err := jsoniter.Marshal(resource)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package gateway_service_account_v2

import (
"context"
"testing"

ctlresource "github.com/conduktor/ctl/resource"
"github.com/conduktor/terraform-provider-conduktor/internal/model"
"github.com/conduktor/terraform-provider-conduktor/internal/test"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stretchr/testify/assert"
)

func TestGatewayServiceAccountV2ModelMapping(t *testing.T) {

ctx := context.Background()

jsonServiceAccountV2Resource := []byte(test.TestAccTestdata(t, "gateway_service_account_v2_api.json"))

ctlResource := ctlresource.Resource{}
err := ctlResource.UnmarshalJSON(jsonServiceAccountV2Resource)
if err != nil {
t.Fatal(err)
return
}
assert.Equal(t, "GatewayServiceAccount", ctlResource.Kind)
assert.Equal(t, "gateway/v2", ctlResource.Version)
assert.Equal(t, "user1", ctlResource.Name)
assert.Equal(t, map[string]interface{}{"name": "user1", "vCluster": "vcluster1"}, ctlResource.Metadata)
assert.Equal(t, jsonServiceAccountV2Resource, ctlResource.Json)

// convert into internal model
internal, err := model.NewGatewayServiceAccountResourceFromClientResource(ctlResource)
if err != nil {
t.Fatal(err)
return
}
assert.Equal(t, "GatewayServiceAccount", internal.Kind)
assert.Equal(t, "gateway/v2", internal.ApiVersion)
assert.Equal(t, "user1", internal.Metadata.Name)
assert.Equal(t, "EXTERNAL", internal.Spec.Type)
assert.Equal(t, []string{"externalName"}, internal.Spec.ExternalNames)

// convert to terraform model
tfModel, err := InternalModelToTerraform(ctx, &internal)
if err != nil {
t.Fatal(err)
return
}
assert.Equal(t, types.StringValue("user1"), tfModel.Name)
assert.Equal(t, types.StringValue("EXTERNAL"), tfModel.Spec.SpecType)
// do not test ExternalNames as it's a pain to parse SetValue

// convert back to internal model
internal2, err := TFToInternalModel(ctx, &tfModel)
if err != nil {
t.Fatal(err)
return
}
assert.Equal(t, "GatewayServiceAccount", internal2.Kind)
assert.Equal(t, "gateway/v2", internal2.ApiVersion)
assert.Equal(t, "user1", internal2.Metadata.Name)
assert.Equal(t, "vcluster1", internal2.Metadata.VCluster)
assert.Equal(t, "EXTERNAL", internal2.Spec.Type)
assert.Equal(t, []string{"externalName"}, internal2.Spec.ExternalNames)

// convert back to ctl model
ctlResource2, err := internal2.ToClientResource()
if err != nil {
t.Fatal(err)
return
}
// compare without json
if !cmp.Equal(ctlResource, ctlResource2, cmpopts.IgnoreFields(ctlresource.Resource{}, "Json")) {
t.Errorf("expected %+v, got %+v", ctlResource, ctlResource2)
}
}
2 changes: 1 addition & 1 deletion internal/model/gateway_service_account_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

const GatewayServiceAccountV2Kind = "GatewayServiceAccount"
const GatewayServiceAccountV2ApiVersion = "v2"
const GatewayServiceAccountV2ApiVersion = "gateway/v2"

type GatewayServiceAccountMetadata struct {
Name string `json:"name"`
Expand Down
10 changes: 8 additions & 2 deletions internal/provider/gateway_service_account_v2_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,14 @@ func (r *GatewayServiceAccountV2Resource) Read(ctx context.Context, req resource
return
}

// Only appending vcluster if present
queryString := "name=" + data.Name.ValueString()
if data.Vcluster.ValueString() != "" {
queryString += "&vcluster=" + data.Vcluster.ValueString()
}

tflog.Info(ctx, fmt.Sprintf("Read service account named %s", data.Name.String()))
get, err := r.apiClient.Describe(ctx, fmt.Sprintf("%s?vcluster=%s&name=%s", gatewayServiceAccountV2ApiPath, data.Vcluster.ValueString(), data.Name.ValueString()))
get, err := r.apiClient.Describe(ctx, fmt.Sprintf("%s?%s", gatewayServiceAccountV2ApiPath, queryString))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read service account, got error: %s", err))
return
Expand All @@ -135,7 +141,7 @@ func (r *GatewayServiceAccountV2Resource) Read(ctx context.Context, req resource

var gatewayRes = []model.GatewayServiceAccountResource{}
err = json.Unmarshal(get, &gatewayRes)
if err != nil {
if err != nil || len(gatewayRes) < 1 {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read service account, got error: %s", err))
return
}
Expand Down
103 changes: 103 additions & 0 deletions internal/provider/gateway_service_account_v2_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package provider

import (
"testing"

"github.com/conduktor/terraform-provider-conduktor/internal/test"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func TestAccGatewayServiceAccountV2Resource(t *testing.T) {
test.CheckEnterpriseEnabled(t)
resourceRef := "conduktor_gateway_service_account_v2.test"
resource.Test(t, resource.TestCase{
PreCheck: func() { test.TestAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and Read testing
{
Config: providerConfig + test.TestAccTestdata(t, "gateway_service_account_v2_resource_create.tf"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceRef, "name", "user1"),
resource.TestCheckResourceAttr(resourceRef, "vcluster", "passthrough"),
resource.TestCheckResourceAttr(resourceRef, "spec.type", "EXTERNAL"),
resource.TestCheckResourceAttr(resourceRef, "spec.external_names.#", "1"),
resource.TestCheckResourceAttr(resourceRef, "spec.external_names.0", "externalName"),
),
},
// Importing matches the state of the previous step.
{
ResourceName: resourceRef,
ImportState: true,
ImportStateVerify: true,
ImportStateId: "user1",
ImportStateVerifyIdentifierAttribute: "name",
},
// Update and Read testing
{
Config: providerConfig + test.TestAccTestdata(t, "gateway_service_account_v2_resource_update.tf"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceRef, "name", "user1"),
resource.TestCheckResourceAttr(resourceRef, "vcluster", "passthrough"),
resource.TestCheckResourceAttr(resourceRef, "spec.type", "EXTERNAL"),
resource.TestCheckResourceAttr(resourceRef, "spec.external_names.#", "1"),
resource.TestCheckResourceAttr(resourceRef, "spec.external_names.0", "newExternalName"),
),
},
// Delete testing automatically occurs in TestCase
},
})
}

func TestAccGatewayServiceAccountV2Minimal(t *testing.T) {
test.CheckEnterpriseEnabled(t)
resource.Test(t, resource.TestCase{
PreCheck: func() { test.TestAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and Read from minimal example
{
Config: providerConfig + test.TestAccTestdata(t, "gateway_service_account_v2_resource_minimal.tf"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.minimal", "name", "minimal"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.minimal", "vcluster", "passthrough"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.minimal", "spec.type", "LOCAL"),
),
},
// Delete testing automatically occurs in TestCase
},
})
}

func TestAccGatewayServiceAccountV2ExampleResource(t *testing.T) {
test.CheckEnterpriseEnabled(t)
resource.Test(t, resource.TestCase{
PreCheck: func() { test.TestAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,

Steps: []resource.TestStep{
// Create and Read from simple example
{
Config: providerConfig + test.TestAccExample(t, "resources", "conduktor_gateway_service_account_v2", "simple.tf"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "name", "simple-service-account"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "vcluster", "passthrough"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "spec.type", "LOCAL"),
),
},
// Create and Read from complex example
{
Config: providerConfig + test.TestAccExample(t, "resources", "conduktor_gateway_service_account_v2", "complex.tf"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "name", "complex-service-account"),
// TODO: Add vcluster tests - Needs gateway_vclusters to be deployed by terraform
// resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "vcluster", "vcluster1"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "spec.type", "EXTERNAL"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "spec.external_names.#", "1"),
resource.TestCheckResourceAttr("conduktor_gateway_service_account_v2.example", "spec.external_names.0", "externalName"),
),
},
},
})
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/schema/validation/schema_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,5 @@ var ValidKafkaConnectSecurityTypes = []string{
SSLAuthKafkaConnectSecurity,
}

// Gateway Service Accounlts
// Gateway Service Accounts.
var ValidServiceAccountTypes = []string{"LOCAL", "EXTERNAL"}
14 changes: 14 additions & 0 deletions internal/testdata/gateway_service_account_v2_api.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"kind": "GatewayServiceAccount",
"apiVersion": "gateway/v2",
"metadata": {
"name": "user1",
"vCluster": "vcluster1"
},
"spec": {
"type": "EXTERNAL",
"externalNames": [
"externalName"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

resource "conduktor_gateway_service_account_v2" "test" {
name = "user1"
spec {
type = "EXTERNAL"
external_names = ["externalName"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

resource "conduktor_gateway_service_account_v2" "minimal" {
name = "minimal"
spec {
type = "LOCAL"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

resource "conduktor_gateway_service_account_v2" "test" {
name = "user1"
spec {
type = "EXTERNAL"
external_names = ["newExternalName"]
}
}

2 changes: 1 addition & 1 deletion provider_code_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@
{
"name": "type",
"string": {
"description": "The type of the Service Accound. Can only be either LOCAL or EXTERNAL. Default value is LOCAL.",
"description": "The type of the Service Accound. Can only be either LOCAL or EXTERNAL.",
"computed_optional_required": "required",
"validators": [
{
Expand Down

0 comments on commit aee2e28

Please sign in to comment.