Skip to content

Commit

Permalink
Merge pull request #602 from pkulik0/data-source-jaas-group
Browse files Browse the repository at this point in the history
#602

## Description

This PR adds a data source for JAAS groups. Additionally it removes unused arguments from jaas client methods and upgrades the version of `jimm-go-sdk`.

Issue: #604 

## Type of change

- Add new resource
- Other - changes to jaas client

## QA steps

Run this against a JAAS controller:

```
terraform {
 required_providers {
 juju = {
 version = ">= 0.15.0"
 source = "juju/juju"
 }
 }
}

resource "juju_jaas_group" "test" {
 name = "group-0"
}

data "juju_jaas_group" "test" {
 name = juju_jaas_group.test.name
}

output "group_uuid" {
 value = data.juju_jaas_group.test.uuid
}
```
  • Loading branch information
jujubot authored Dec 3, 2024
2 parents a3e7b30 + 298fcd7 commit c271cfd
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 22 deletions.
40 changes: 40 additions & 0 deletions docs/data-sources/jaas_group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "juju_jaas_group Data Source - terraform-provider-juju"
subcategory: ""
description: |-
A data source representing a Juju JAAS Group.
---

# juju_jaas_group (Data Source)

A data source representing a Juju JAAS Group.

## Example Usage

```terraform
resource "juju_jaas_group" "test" {
name = "group-0"
}
data "juju_jaas_group" "test" {
name = juju_jaas_group.test.name
// from a separate plan use a string literal
// name = "group-0"
}
output "group_uuid" {
value = data.juju_jaas_group.test.uuid
}
```

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

### Required

- `name` (String) The name of the group.

### Read-Only

- `uuid` (String) The UUID of the group.
13 changes: 13 additions & 0 deletions examples/data-sources/juju_jaas_group/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
resource "juju_jaas_group" "test" {
name = "group-0"
}

data "juju_jaas_group" "test" {
name = juju_jaas_group.test.name
// from a separate plan use a string literal
// name = "group-0"
}

output "group_uuid" {
value = data.juju_jaas_group.test.uuid
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
)

require (
github.com/canonical/jimm-go-sdk/v3 v3.0.4
github.com/canonical/jimm-go-sdk/v3 v3.0.5
github.com/dustin/go-humanize v1.0.1
github.com/hashicorp/terraform-json v0.22.1
github.com/hashicorp/terraform-plugin-framework v1.11.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/canonical/go-dqlite v1.21.0 h1:4gLDdV2GF+vg0yv9Ff+mfZZNQ1JGhnQ3GnS2GeZPHfA=
github.com/canonical/go-dqlite v1.21.0/go.mod h1:Uvy943N8R4CFUAs59A1NVaziWY9nJ686lScY7ywurfg=
github.com/canonical/jimm-go-sdk/v3 v3.0.4 h1:cWNL6GIFbwB2W//PaOTjoVuRVloQ8P+3YIm26KiBs10=
github.com/canonical/jimm-go-sdk/v3 v3.0.4/go.mod h1:xcJrWTpLHSw3Z16/1Zcvh31awlwIzjXdrYUYCVZhc5s=
github.com/canonical/jimm-go-sdk/v3 v3.0.5 h1:eQvn35wlmv+uNfyB7FHm+SkCigBu0x2VS1FlsaNor4Q=
github.com/canonical/jimm-go-sdk/v3 v3.0.5/go.mod h1:xcJrWTpLHSw3Z16/1Zcvh31awlwIzjXdrYUYCVZhc5s=
github.com/canonical/lxd v0.0.0-20231214113525-e676fc63c50a h1:Tfo/MzXK5GeG7gzSHqxGeY/669Mhh5ea43dn1mRDnk8=
github.com/canonical/lxd v0.0.0-20231214113525-e676fc63c50a/go.mod h1:UxfHGKFoRjgu1NUA9EFiR++dKvyAiT0h9HT0ffMlzjc=
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
Expand Down
22 changes: 15 additions & 7 deletions internal/juju/jaas.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (jc *jaasClient) ReadRelations(ctx context.Context, tuple *JaasTuple) ([]Ja
}

// AddGroup attempts to create a new group with the provided name.
func (jc *jaasClient) AddGroup(ctx context.Context, name string) (string, error) {
func (jc *jaasClient) AddGroup(name string) (string, error) {
conn, err := jc.GetConnection(nil)
if err != nil {
return "", err
Expand All @@ -167,25 +167,33 @@ func (jc *jaasClient) AddGroup(ctx context.Context, name string) (string, error)
return resp.UUID, nil
}

// ReadGroup attempts to read a group that matches the provided UUID.
func (jc *jaasClient) ReadGroup(ctx context.Context, uuid string) (*JaasGroup, error) {
// ReadGroupByUUID attempts to read a group that matches the provided UUID.
func (jc *jaasClient) ReadGroupByUUID(uuid string) (*JaasGroup, error) {
return jc.readGroup(&params.GetGroupRequest{UUID: uuid})
}

// ReadGroupByName attempts to read a group that matches the provided name.
func (jc *jaasClient) ReadGroupByName(name string) (*JaasGroup, error) {
return jc.readGroup(&params.GetGroupRequest{Name: name})
}

func (jc *jaasClient) readGroup(req *params.GetGroupRequest) (*JaasGroup, error) {
conn, err := jc.GetConnection(nil)
if err != nil {
return nil, err
}
defer func() { _ = conn.Close() }()

client := jc.getJaasApiClient(conn)
req := params.GetGroupRequest{UUID: uuid}
resp, err := client.GetGroup(&req)
resp, err := client.GetGroup(req)
if err != nil {
return nil, err
}
return &JaasGroup{Name: resp.Name, UUID: resp.UUID}, nil
}

// RenameGroup attempts to rename a group that matches the provided name.
func (jc *jaasClient) RenameGroup(ctx context.Context, name, newName string) error {
func (jc *jaasClient) RenameGroup(name, newName string) error {
conn, err := jc.GetConnection(nil)
if err != nil {
return err
Expand All @@ -198,7 +206,7 @@ func (jc *jaasClient) RenameGroup(ctx context.Context, name, newName string) err
}

// RemoveGroup attempts to remove a group that matches the provided name.
func (jc *jaasClient) RemoveGroup(ctx context.Context, name string) error {
func (jc *jaasClient) RemoveGroup(name string) error {
conn, err := jc.GetConnection(nil)
if err != nil {
return err
Expand Down
10 changes: 5 additions & 5 deletions internal/juju/jaas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (s *JaasSuite) TestAddGroup() {
s.mockJaasClient.EXPECT().AddGroup(req).Return(resp, nil)

client := s.getJaasClient()
uuid, err := client.AddGroup(context.Background(), name)
uuid, err := client.AddGroup(name)
s.Require().NoError(err)
s.Require().Equal(resp.UUID, uuid)
}
Expand All @@ -179,7 +179,7 @@ func (s *JaasSuite) TestGetGroup() {
s.mockJaasClient.EXPECT().GetGroup(req).Return(resp, nil)

client := s.getJaasClient()
gotGroup, err := client.ReadGroup(context.Background(), uuid)
gotGroup, err := client.ReadGroupByUUID(uuid)
s.Require().NoError(err)
s.Require().Equal(*gotGroup, JaasGroup{UUID: uuid, Name: name})
}
Expand All @@ -193,7 +193,7 @@ func (s *JaasSuite) TestGetGroupNotFound() {
s.mockJaasClient.EXPECT().GetGroup(req).Return(params.GetGroupResponse{}, errors.New("group not found"))

client := s.getJaasClient()
gotGroup, err := client.ReadGroup(context.Background(), uuid)
gotGroup, err := client.ReadGroupByUUID(uuid)
s.Require().Error(err)
s.Require().Nil(gotGroup)
}
Expand All @@ -207,7 +207,7 @@ func (s *JaasSuite) TestRenameGroup() {
s.mockJaasClient.EXPECT().RenameGroup(req).Return(nil)

client := s.getJaasClient()
err := client.RenameGroup(context.Background(), name, newName)
err := client.RenameGroup(name, newName)
s.Require().NoError(err)
}

Expand All @@ -219,7 +219,7 @@ func (s *JaasSuite) TestRemoveGroup() {
s.mockJaasClient.EXPECT().RemoveGroup(req).Return(nil)

client := s.getJaasClient()
err := client.RemoveGroup(context.Background(), name)
err := client.RemoveGroup(name)
s.Require().NoError(err)
}

Expand Down
115 changes: 115 additions & 0 deletions internal/provider/data_source_jaas_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2024 Canonical Ltd.
// Licensed under the Apache License, Version 2.0, see LICENCE file for details.

package provider

import (
"context"
"fmt"

"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"

"github.com/juju/terraform-provider-juju/internal/juju"
)

type jaasGroupDataSource struct {
client *juju.Client

// subCtx is the context created with the new tflog subsystem for applications.
subCtx context.Context
}

// NewJAASGroupDataSource returns a new JAAS group data source instance.
func NewJAASGroupDataSource() datasource.DataSource {
return &jaasGroupDataSource{}
}

type jaasGroupDataSourceModel struct {
Name types.String `tfsdk:"name"`
UUID types.String `tfsdk:"uuid"`
}

// Metadata returns the metadata for the JAAS group data source.
func (d *jaasGroupDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_jaas_group"
}

// Schema defines the schema for JAAS groups.
func (d *jaasGroupDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "A data source representing a Juju JAAS Group.",
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "The name of the group.",
Required: true,
},
"uuid": schema.StringAttribute{
Description: "The UUID of the group.",
Computed: true,
},
},
}
}

// Configure sets up the JAAS group data source with the provider data.
func (d *jaasGroupDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

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

d.client = client
d.subCtx = tflog.NewSubsystem(ctx, LogDataSourceJAASGroup)
}

// Read updates the group data source with the latest data from JAAS.
func (d *jaasGroupDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
// Prevent panic if the provider has not been configured.
if d.client == nil {
addDSClientNotConfiguredError(&resp.Diagnostics, "jaas-group")
return
}

var data jaasGroupDataSourceModel

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

// Update the group with the latest data from JAAS
group, err := d.client.Jaas.ReadGroupByName(data.Name.String())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read group, got error: %v", err))
return
}
data.UUID = types.StringValue(group.UUID)
d.trace(fmt.Sprintf("read group %q data source", data.Name))

// Save the updated group back to the state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (d *jaasGroupDataSource) trace(msg string, additionalFields ...map[string]interface{}) {
if d.subCtx == nil {
return
}

//SubsystemTrace(subCtx, "datasource-jaas-group", "hello, world", map[string]interface{}{"foo": 123})
// Output:
// {"@level":"trace","@message":"hello, world","@module":"juju.datasource-jaas-group","foo":123}
tflog.SubsystemTrace(d.subCtx, LogDataSourceJAASGroup, msg, additionalFields...)
}
49 changes: 49 additions & 0 deletions internal/provider/data_source_jaas_group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2024 Canonical Ltd.
// Licensed under the Apache License, Version 2.0, see LICENCE file for details.

package provider

import (
"testing"

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

internaltesting "github.com/juju/terraform-provider-juju/internal/testing"
)

func TestAcc_DataSourceJAASGroup(t *testing.T) {
OnlyTestAgainstJAAS(t)
groupName := acctest.RandomWithPrefix("tf-jaas-group")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: frameworkProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccDataSourceJAASGroup(groupName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.juju_jaas_group.test", "name", groupName),
resource.TestCheckResourceAttrSet("data.juju_jaas_group.test", "uuid"),
resource.TestCheckResourceAttrPair("juju_jaas_group.test", "uuid", "data.juju_jaas_group.test", "uuid"),
),
},
},
})
}

func testAccDataSourceJAASGroup(name string) string {
return internaltesting.GetStringFromTemplateWithData(
"testAccDataSourceJAASGroup",
`
resource "juju_jaas_group" "test" {
name = "{{ .Name }}"
}
data "juju_jaas_group" "test" {
name = juju_jaas_group.test.name
}
`, internaltesting.TemplateData{
"Name": name,
})
}
2 changes: 2 additions & 0 deletions internal/provider/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const (
LogResourceSecret = "resource-secret"
LogResourceAccessSecret = "resource-access-secret"

LogDataSourceJAASGroup = "datasource-jaas-group"

LogResourceJAASAccessModel = "resource-jaas-access-model"
LogResourceJAASAccessCloud = "resource-jaas-access-cloud"
LogResourceJAASAccessGroup = "resource-jaas-access-group"
Expand Down
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ func (p *jujuProvider) DataSources(_ context.Context) []func() datasource.DataSo
func() datasource.DataSource { return NewModelDataSource() },
func() datasource.DataSource { return NewOfferDataSource() },
func() datasource.DataSource { return NewSecretDataSource() },
func() datasource.DataSource { return NewJAASGroupDataSource() },
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/provider/resource_access_jaas_offer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestAcc_ResourceJaasAccessOffer(t *testing.T) {
// Objects for checking access
groupRelationF := func(s string) string { return jimmnames.NewGroupTag(s).String() + "#member" }
groupCheck := newCheckAttribute(groupResourcename, "uuid", groupRelationF)
offerRelationF := func(s string) string { return jimmnames.NewApplicationOfferTag(s).String() }
offerRelationF := func(s string) string { return names.NewApplicationOfferTag(s).String() }
offerCheck := newCheckAttribute(offerAccessResourceName, "offer_url", offerRelationF)
userTag := names.NewUserTag(user).String()
svcAccTag := names.NewUserTag(svcAccWithDomain).String()
Expand Down
Loading

0 comments on commit c271cfd

Please sign in to comment.