Skip to content

Commit

Permalink
feat(LH-70474): Add tenant data source (#42)
Browse files Browse the repository at this point in the history
This commit adds a new tenant data source that provides information on the currently logged in tenant.
  • Loading branch information
siddhuwarrier authored Sep 12, 2023
1 parent 26e5281 commit a8cb2ac
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 2 deletions.
8 changes: 7 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ package client

import (
"context"
"net/http"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/connector"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/asa/asaconfig"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/cloudftd"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/genericssh"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/tenant"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/user"
"net/http"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/ios"
Expand Down Expand Up @@ -170,3 +172,7 @@ func (c *Client) GenerateApiToken(ctx context.Context, inp user.GenerateApiToken
func (c *Client) RevokeApiToken(ctx context.Context, inp user.RevokeApiTokenInput) (*user.RevokeApiTokenOutput, error) {
return user.RevokeApiToken(ctx, c.client, inp)
}

func (c *Client) ReadTenantDetails(ctx context.Context) (*tenant.ReadTenantDetailsOutput, error) {
return tenant.ReadTenantDetails(ctx, c.client)
}
5 changes: 5 additions & 0 deletions client/internal/url/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package url

import (
"fmt"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/devicetype"
)

Expand Down Expand Up @@ -112,3 +113,7 @@ func GenerateApiToken(baseUrl string, username string) string {
func RevokeApiToken(baseUrl string, tokenId string) string {
return fmt.Sprintf("%s/anubis/rest/v1/oauth/revoke/%s", baseUrl, tokenId)
}

func ReadTenantDetails(baseUrl string) string {
return fmt.Sprintf("%s/anubis/rest/v1/oauth/check_token", baseUrl)
}
5 changes: 5 additions & 0 deletions client/tenant/fixtures_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package tenant_test

const (
baseUrl = "https://unittest.cdo.cisco.com"
)
16 changes: 16 additions & 0 deletions client/tenant/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tenant

type TenantDetailsDetails struct {
TenantName string `json:"TenantName"`
TenantOrganizationName string `json:"TenantOrganizationName"`
TenantPayType string `json:"TenantPayType"`
TenantUid string `json:"TenantUid"`
}

type UserAuthentication struct {
Details TenantDetailsDetails `json:"details"`
}

type ReadTenantDetailsOutput struct {
UserAuthentication UserAuthentication `json:"userAuthentication"`
}
26 changes: 26 additions & 0 deletions client/tenant/read_tenant_details.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tenant

import (
"context"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/url"
)

func ReadTenantDetails(ctx context.Context, client http.Client) (*ReadTenantDetailsOutput, error) {
client.Logger.Println("Get tenant details for currently connected client")

req := NewReadTenantDetailsRequest(ctx, client)

var outp ReadTenantDetailsOutput
if err := req.Send(&outp); err != nil {
return nil, err
}

return &outp, nil
}

func NewReadTenantDetailsRequest(ctx context.Context, client http.Client) *http.Request {
url := url.ReadTenantDetails(client.BaseUrl())
return client.NewGet(ctx, url)
}
55 changes: 55 additions & 0 deletions client/tenant/read_tenant_details_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package tenant_test

import (
"context"
netHttp "net/http"
"testing"
"time"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/tenant"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
)

func TestReadTenantDetails(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

t.Run("Should get current tenant details", func(t *testing.T) {
httpmock.Reset()
expected := tenant.ReadTenantDetailsOutput{
UserAuthentication: tenant.UserAuthentication{
Details: tenant.TenantDetailsDetails{
TenantUid: "111-111-111-111",
TenantName: "sample-tenant-name",
TenantOrganizationName: "sample-org-name",
TenantPayType: "NOT_PAYING",
},
},
}
httpmock.RegisterResponder(
netHttp.MethodGet,
"/anubis/rest/v1/oauth/check_token",
httpmock.NewJsonResponderOrPanic(200, expected),
)

actual, err := tenant.ReadTenantDetails(context.Background(), *http.MustNewWithConfig(baseUrl, "valid token", 0, 0, time.Minute))
assert.NotNil(t, actual, "Read output should not be nil")
assert.Equal(t, *actual, expected)
assert.Nil(t, err, "error should be nil")
})

t.Run("should error if getting current tenant details fails", func(t *testing.T) {
httpmock.Reset()
httpmock.RegisterResponder(
netHttp.MethodGet,
"/anubis/rest/v1/oauth/check_token",
httpmock.NewJsonResponderOrPanic(500, nil),
)

actual, err := tenant.ReadTenantDetails(context.Background(), *http.MustNewWithConfig(baseUrl, "valid token", 0, 0, time.Minute))
assert.Nil(t, actual, "Read output should be nil")
assert.NotNil(t, err, "error should not be nil")
})
}
23 changes: 23 additions & 0 deletions docs/data-sources/tenant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "cdo_tenant Data Source - cdo"
subcategory: ""
description: |-
Use this data source to get information on the tenant upon which the Terraform provider is performing operations.
---

# cdo_tenant (Data Source)

Use this data source to get information on the tenant upon which the Terraform provider is performing operations.



<!-- schema generated by tfplugindocs -->
## Schema

### Read-Only

- `human_readable_name` (String) Human-readable name of the tenant as displayed on the CDO UI (if different from the tenant name).
- `id` (String) Universally unique identifier for the tenant.
- `name` (String) Name of the tenant.
- `subscription_type` (String) The type of CDO subscription used on this tenant.
31 changes: 31 additions & 0 deletions provider/examples/data-sources/tenant/example.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
terraform {
required_providers {
cdo = {
source = "hashicorp.com/CiscoDevnet/cdo"
}
}
}

provider "cdo" {
base_url = "<https://www.defenseorchestrator.com|https://www.defenseorchestrator.eu|https://apj.cdo.cisco.com>"
api_token = "<replace-with-api-token-generated-from-cdo>"
}

data "cdo_tenant" "current" {
}

output "current_tenant_uid" {
value = data.cdo_tenant.current.id
}

output "current_tenant_name" {
value = data.cdo_tenant.current.name
}

output "current_tenant_human_readable_name" {
value = data.cdo_tenant.current.human_readable_name
}

output "current_tenant_subscription_type" {
value = data.cdo_tenant.current.subscription_type
}
5 changes: 4 additions & 1 deletion provider/internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ package provider
import (
"context"
"fmt"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/device/ftd"
"os"

"github.com/CiscoDevnet/terraform-provider-cdo/internal/device/ftd"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/tenant"

"github.com/CiscoDevnet/terraform-provider-cdo/internal/connector"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/user"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/user_api_token"
Expand Down Expand Up @@ -163,6 +165,7 @@ func (p *CdoProvider) DataSources(ctx context.Context) []func() datasource.DataS
asa.NewAsaDataSource,
ios.NewIosDataSource,
user.NewDataSource,
tenant.NewDataSource,
}
}

Expand Down
Binary file added provider/internal/tenant/__debug_bin683841204
Binary file not shown.
100 changes: 100 additions & 0 deletions provider/internal/tenant/data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package tenant

import (
"context"
"fmt"

cdoClient "github.com/CiscoDevnet/terraform-provider-cdo/go-client"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

type DataSourceModel struct {
Uid types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
HumanReadableName types.String `tfsdk:"human_readable_name"`
SubscriptionType types.String `tfsdk:"subscription_type"`
}

func NewDataSource() datasource.DataSource {
return &DataSource{}
}

type DataSource struct {
client *cdoClient.Client
}

func (d *DataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_tenant"
}

func (d *DataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Use this data source to get information on the tenant upon which the Terraform provider is performing operations.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "Universally unique identifier for the tenant.",
Computed: true,
},
"name": schema.StringAttribute{
MarkdownDescription: "Name of the tenant.",
Computed: true,
},
"human_readable_name": schema.StringAttribute{
MarkdownDescription: "Human-readable name of the tenant as displayed on the CDO UI (if different from the tenant name).",
Computed: true,
},
"subscription_type": schema.StringAttribute{
MarkdownDescription: "The type of CDO subscription used on this tenant.",
Computed: true,
},
},
}
}

func (d *DataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*cdoClient.Client)

if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *cdoClient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = client
}

func (d *DataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {

var planData DataSourceModel

// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &planData)...)
if resp.Diagnostics.HasError() {
return
}

res, err := d.client.ReadTenantDetails(ctx)
if err != nil {
resp.Diagnostics.AddError("Failed to read tenant", err.Error())
return
}

planData.Uid = types.StringValue(res.UserAuthentication.Details.TenantUid)
planData.Name = types.StringValue(res.UserAuthentication.Details.TenantName)
planData.HumanReadableName = types.StringValue(res.UserAuthentication.Details.TenantOrganizationName)
planData.SubscriptionType = types.StringValue(res.UserAuthentication.Details.TenantPayType)
tflog.Debug(ctx, fmt.Sprintf("Read tenant details %+v", planData))

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &planData)...)
}
44 changes: 44 additions & 0 deletions provider/internal/tenant/data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tenant_test

import (
"testing"

"github.com/CiscoDevnet/terraform-provider-cdo/internal/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

var testTenant = struct {
Name string
Uid string
HumanReadableName string
SubscriptionType string
}{
Name: "CDO_terraform-provider-cdo",
Uid: "ae98d25f-1089-4286-a3c5-505dcb4431a2",
HumanReadableName: "terraform-provider-cdo",
SubscriptionType: "INTERNAL",
}

const testTenantTemplate = `
data "cdo_tenant" "test" {}`

var testTenantConfig = acctest.MustParseTemplate(testTenantTemplate, testTenant)

func TestAccTenantDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: acctest.PreCheckFunc(t),
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Read testing
{
Config: acctest.ProviderConfig() + testTenantConfig,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.cdo_tenant.test", "name", testTenant.Name),
resource.TestCheckResourceAttr("data.cdo_tenant.test", "id", testTenant.Uid),
resource.TestCheckResourceAttr("data.cdo_tenant.test", "human_readable_name", testTenant.HumanReadableName),
resource.TestCheckResourceAttr("data.cdo_tenant.test", "subscription_type", testTenant.SubscriptionType),
),
},
},
})
}

0 comments on commit a8cb2ac

Please sign in to comment.