Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add juju_access_offer resource #633

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/resources/access_offer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "juju_access_offer Resource - terraform-provider-juju"
subcategory: ""
description: |-
A resource that represent a Juju Access Offer. Warning: Do not repeat users across different access levels.
---

# juju_access_offer (Resource)

A resource that represent a Juju Access Offer. Warning: Do not repeat users across different access levels.

## Example Usage

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: add examples/resource/juju_access_offer directory with resource.tf and import.sh files, content will be added to this markdown file during make install.

```terraform
resource "juju_access_offer" "this" {
offer_url = juju_offer.my_application_offer.url
consume = [juju_user.dev.name]
}
```

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

### Required

- `offer_url` (String) The url of the offer for access management. If this is changed the resource will be deleted and a new resource will be created.

### Optional

- `admin` (Set of String) List of users to grant admin access. "admin" user is not allowed.
- `consume` (Set of String) List of users to grant consume access. "admin" user is not allowed.
- `read` (Set of String) List of users to grant read access. "admin" user is not allowed.

### Read-Only

- `id` (String) The ID of this resource.

## Import

Import is supported using the following syntax:

```shell
# Access Offers can be imported by using the Offer URL as in the juju show-offers output.
# Example:
# $juju show-offer mysql
# Store URL Access Description Endpoint Interface Role
# mycontroller admin/db.mysql admin MariaDB Server is one of the most ... mysql mysql provider
$ terraform import juju_access_offer.db admin/db.mysql
```
6 changes: 6 additions & 0 deletions examples/resources/juju_access_offer/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Access Offers can be imported by using the Offer URL as in the juju show-offers output.
# Example:
# $juju show-offer mysql
# Store URL Access Description Endpoint Interface Role
# mycontroller admin/db.mysql admin MariaDB Server is one of the most ... mysql mysql provider
$ terraform import juju_access_offer.db admin/db.mysql
4 changes: 4 additions & 0 deletions examples/resources/juju_access_offer/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "juju_access_offer" "this" {
offer_url = juju_offer.my_application_offer.url
consume = [juju_user.dev.name]
}
65 changes: 63 additions & 2 deletions internal/juju/offers.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type ReadOfferResponse struct {
ModelName string
Name string
OfferURL string
Users []crossmodel.OfferUserDetails
}

type DestroyOfferInput struct {
Expand All @@ -74,12 +75,19 @@ type RemoveRemoteOfferInput struct {
OfferURL string
}

type GrantRevokeOfferInput struct {
Users []string
Access string
OfferURL string
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be URL's, you can revoke many at once

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we discussed changing the schema in the last terraform office hours, I think this no longer apply, WDYT?

}

func newOffersClient(sc SharedClient) *offersClient {
return &offersClient{
SharedClient: sc,
}
}

// CreateOffer creates offer managed by the offer resource.
func (c offersClient) CreateOffer(input *CreateOfferInput) (*CreateOfferResponse, []error) {
var errs []error

Expand Down Expand Up @@ -152,6 +160,7 @@ func (c offersClient) CreateOffer(input *CreateOfferInput) (*CreateOfferResponse
return &resp, nil
}

// ReadOffer reads offer managed by the offer resource.
func (c offersClient) ReadOffer(input *ReadOfferInput) (*ReadOfferResponse, error) {
conn, err := c.GetConnection(nil)
if err != nil {
Expand All @@ -170,6 +179,7 @@ func (c offersClient) ReadOffer(input *ReadOfferInput) (*ReadOfferResponse, erro
response.ApplicationName = result.ApplicationName
response.OfferURL = result.OfferURL
response.Endpoint = result.Endpoints[0].Name
response.Users = result.Users

//no model name is returned but it can be parsed from the resulting offer URL to ensure parity
//TODO: verify if we can fetch information another way
Expand All @@ -182,6 +192,7 @@ func (c offersClient) ReadOffer(input *ReadOfferInput) (*ReadOfferResponse, erro
return &response, nil
}

// DestroyOffer destroys offer managed by the offer resource.
func (c offersClient) DestroyOffer(input *DestroyOfferInput) error {
conn, err := c.GetConnection(nil)
if err != nil {
Expand Down Expand Up @@ -249,7 +260,7 @@ func parseModelFromURL(url string) (result string, success bool) {
return result, true
}

// This function allows the integration resource to consume the offers managed by the offer resource
// ConsumeRemoteOffer allows the integration resource to consume the offers managed by the offer resource.
func (c offersClient) ConsumeRemoteOffer(input *ConsumeRemoteOfferInput) (*ConsumeRemoteOfferResponse, error) {
modelConn, err := c.GetConnection(&input.ModelName)
if err != nil {
Expand Down Expand Up @@ -330,7 +341,7 @@ func (c offersClient) ConsumeRemoteOffer(input *ConsumeRemoteOfferInput) (*Consu
return &response, nil
}

// This function allows the integration resource to destroy the offers managed by the offer resource
// RemoveRemoteOffer allows the integration resource to destroy the offers managed by the offer resource.
func (c offersClient) RemoveRemoteOffer(input *RemoveRemoteOfferInput) []error {
var errors []error
conn, err := c.GetConnection(&input.ModelName)
Expand Down Expand Up @@ -390,3 +401,53 @@ func (c offersClient) RemoveRemoteOffer(input *RemoveRemoteOfferInput) []error {

return nil
}

// GrantOffer adds access to an offer managed by the access offer resource.
// No action or error if the access was already granted to the user.
func (c offersClient) GrantOffer(input *GrantRevokeOfferInput) error {
conn, err := c.GetConnection(nil)
if err != nil {
return err
}
defer func() { _ = conn.Close() }()

client := applicationoffers.NewClient(conn)

for _, user := range input.Users {
err = client.GrantOffer(user, input.Access, input.OfferURL)
if err != nil {
// ignore if user was already granted
if strings.Contains(err.Error(), "user already has") {
continue
}
return err
}
}

return nil
}

// RevokeOffer revokes access to an offer managed by the access offer resource.
// No action or error if the access was already revoked for the user.
func (c offersClient) RevokeOffer(input *GrantRevokeOfferInput) error {
conn, err := c.GetConnection(nil)
if err != nil {
return err
}
defer func() { _ = conn.Close() }()

client := applicationoffers.NewClient(conn)

for _, user := range input.Users {
err = client.RevokeOffer(user, input.Access, input.OfferURL)
if err != nil {
// ignorer if user was already revoked
if strings.Contains(err.Error(), "not found") {
continue
}
return err
}
}

return nil
}
1 change: 1 addition & 0 deletions internal/provider/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (

LogResourceApplication = "resource-application"
LogResourceAccessModel = "resource-access-model"
LogResourceAccessOffer = "resource-access-offer"
LogResourceCredential = "resource-credential"
LogResourceKubernetesCloud = "resource-kubernetes-cloud"
LogResourceMachine = "resource-machine"
Expand Down
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ func getJujuProviderModel(ctx context.Context, req provider.ConfigureRequest) (j
func (p *jujuProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
func() resource.Resource { return NewAccessModelResource() },
func() resource.Resource { return NewAccessOfferResource() },
func() resource.Resource { return NewApplicationResource() },
func() resource.Resource { return NewCredentialResource() },
func() resource.Resource { return NewIntegrationResource() },
Expand Down
Loading
Loading