Skip to content

Commit

Permalink
(nats-io#129) Add usable operator resource
Browse files Browse the repository at this point in the history
  • Loading branch information
ploubser committed Feb 11, 2025
1 parent d816463 commit 8fbc9e7
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 57 deletions.
58 changes: 31 additions & 27 deletions jetstream/resource_account.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package jetstream

import (
"fmt"
"os"
"path/filepath"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
authb "github.com/synadia-io/jwt-auth-builder.go"
Expand Down Expand Up @@ -103,37 +107,37 @@ func resourceAccountRead(d *schema.ResourceData, m any) error {

// HERE(ploubser): We cannot currently delete system accounts
func resourceAccountDelete(d *schema.ResourceData, m any) error {
/* conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}
conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}

operatorname := d.Get("operator").(string)
operator, err := auth.Operators().Get(operatorname)
if err != nil {
return err
}
operatorname := d.Get("operator").(string)
operator, err := auth.Operators().Get(operatorname)
if err != nil {
return err
}

accountName := d.Get("name").(string)
err = operator.Accounts().Delete(accountName)
if err != nil {
return err
}
accountName := d.Get("name").(string)
err = operator.Accounts().Delete(accountName)
if err != nil {
return err
}

err = auth.Commit()
if err != nil {
return err
}
err = auth.Commit()
if err != nil {
return err
}

// HERE(ploubser): This is temporary while using the NSC provider, since it can't remove accounts
// Delete the accounts' directory
// Are there any other files that need to be deleted?
err = os.RemoveAll(filepath.Join(conf.StoreDirPath, operatorname, "accounts", accountName))
if err != nil {
fmt.Println("Error removing account directory:", err)
}

// HERE(ploubser): This is temporary while using the NSC provider, since it can't remove accounts
// Delete the accounts' directory
// Are there any other files that need to be deleted?
err = os.RemoveAll(filepath.Join(conf.StoreDirPath, operatorname, "accounts", accountName))
if err != nil {
fmt.Println("Error removing account directory:", err)
}
*/
return nil
}

Expand Down
191 changes: 167 additions & 24 deletions jetstream/resource_operator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package jetstream

import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand All @@ -23,20 +28,34 @@ func resourceOperator() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"service_url": {
"operator_service_url": {
Type: schema.TypeString,
Description: "Operator's API endpoint for account-related operations",
Optional: true,
ForceNew: false,
ValidateFunc: validation.StringIsNotEmpty,
},
"account_server_url": {
Type: schema.TypeString,
Description: "",
Description: "HTTP endpoint where NATS servers can dynamically fetch Account JWTs",
Optional: true,
ForceNew: false,
ValidateFunc: validation.StringIsNotEmpty,
},
"tags": {
Type: schema.TypeList,
Description: "",
Description: "Tags to group the operator",
Optional: true,
ForceNew: false,
Elem: &schema.Schema{Type: schema.TypeString},
},
"expiry": {
Type: schema.TypeString,
Description: "Sets an expiration date for the operator JWT, duration specified in seconds",
Optional: true,
ForceNew: false,
ValidateFunc: validation.IsRFC3339Time,
},
// Exported
"public_key": {
Type: schema.TypeString,
Expand All @@ -59,6 +78,39 @@ func resourceOperatorCreate(d *schema.ResourceData, m any) error {
return err
}

serviceUrl := d.Get("operator_service_url").(string)
err = o.SetOperatorServiceURL(serviceUrl)
if err != nil {
return err
}

accountServer := d.Get("account_server_url").(string)
err = o.SetAccountServerURL(accountServer)
if err != nil {
return err
}

tags := []string{}
for _, tag := range d.Get("tags").([]any) {
tags = append(tags, tag.(string))
}

err = o.Tags().Set(tags...)
if err != nil {
return err
}

expiryString := d.Get("expiry").(string)
x, err := time.Parse(time.RFC3339, expiryString)
if err != nil {
return err
}

err = o.SetExpiry(x.Unix())
if err != nil {
return err
}

err = auth.Commit()
if err != nil {
return err
Expand All @@ -70,42 +122,133 @@ func resourceOperatorCreate(d *schema.ResourceData, m any) error {
return nil
}

// TODO
func resourceOperatorRead(d *schema.ResourceData, m any) error {
return nil
}
conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}

func resourceOperatorDelete(d *schema.ResourceData, m any) error {
/* conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}
o, err := auth.Operators().Get(d.Id())
if err != nil {
return err
}

name := d.Get("name").(string)
// This is suppose to do something?
err = auth.Operators().Delete(name)
if err != nil {
return err
}
err = d.Set("name", o.Name())
if err != nil {
return err
}

err = auth.Commit()
if len(o.OperatorServiceURLs()) > 0 {
err = d.Set("operator_service_url", o.OperatorServiceURLs()[0])
if err != nil {
return err
}
}

err = d.Set("account_server_url", o.AccountServerURL())
if err != nil {
return err
}

tags, err := o.Tags().All()
if err != nil {
return err
}

err = d.Set("tags", tags)
if err != nil {
return err
}

err = d.Set("expiry", time.Unix(o.Expiry(), 0).Format(time.RFC3339))
if err != nil {
return err
}

return nil
}

func resourceOperatorDelete(d *schema.ResourceData, m any) error {
conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}

name := d.Get("name").(string)
err = auth.Operators().Delete(name)
if err != nil {
return err
}

err = auth.Commit()
if err != nil {
return err
}

// HERE(ploubser): This is temporary while using the NSC provider, since it can't remove operators
// Delete the operator's directory
// Are there any other files that need to be deleted?
// HERE(ploubser): This is temporary while using the NSC provider, since it can't remove operators
// Delete the operator's directory
// We need to also delete the corresponding key but not sure how to do that without removing the other keys
if conf.AuthBackend == "nsc" {
err = os.RemoveAll(filepath.Join(conf.StoreDirPath, name))
if err != nil {
fmt.Println("Error removing operator directory:", err)
}
*/
}

return nil
}

// TODO
func resourceOperatorUpdate(d *schema.ResourceData, m any) error {
conf := m.(ProviderConfig)
auth, err := NewAuthProvider(conf)
if err != nil {
return err
}

o, err := auth.Operators().Get(d.Id())
if err != nil {
return err
}

serviceUrl := d.Get("operator_service_url").(string)
err = o.SetOperatorServiceURL(serviceUrl)
if err != nil {
return err
}

accountServer := d.Get("account_server_url").(string)
err = o.SetAccountServerURL(accountServer)
if err != nil {
return err
}

tags := []string{}
for _, tag := range d.Get("tags").([]any) {
tags = append(tags, tag.(string))
}

err = o.Tags().Set(tags...)
if err != nil {
return err
}

expiryString := d.Get("expiry").(string)
x, err := time.Parse(time.RFC3339, expiryString)
if err != nil {
return err
}

err = o.SetExpiry(x.Unix())
if err != nil {
return err
}

err = auth.Commit()
if err != nil {
return err
}

return nil
}
15 changes: 9 additions & 6 deletions jetstream/resource_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ provider "jetstream" {
resource "jetstream_operator" "TEST" {
name = "TEST"
service_url = "https://...." // optional
tags = ["foo", "bar"] // optional
operator_service_url = "nats://localhost:4222"
account_server_url = "https://jwt-resolver.example.com"
tags = ["foo", "bar"]
expiry = "2100-02-11T00:00:00Z"
}
`

Expand All @@ -40,16 +42,17 @@ func TestResourceOperator(t *testing.T) {

resource.Test(t, resource.TestCase{
ProviderFactories: testJsProviders,
CheckDestroy: testOperatorDoesnotExist("/tmp/test/store", "TEST2"),
CheckDestroy: testOperatorDoesnotExist("/tmp/test/store", "TEST"),
Steps: []resource.TestStep{
{
Config: testOperatorBasic,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("jetstream_operator.TEST", "public_key"),
resource.TestCheckResourceAttr("jetstream_operator.TEST", "service_url", "https://...."),
resource.TestCheckResourceAttr("jetstream_operator.TEST", "operator_service_url", "nats://localhost:4222"),
resource.TestCheckResourceAttr("jetstream_operator.TEST", "account_server_url", "https://jwt-resolver.example.com"),
resource.TestCheckResourceAttr("jetstream_operator.TEST", "tags.0", "foo"),
resource.TestCheckResourceAttr("jetstream_operator.TEST2", "tags.1", "bar"),
// Check jwt contents and see if it matches what we expect
resource.TestCheckResourceAttr("jetstream_operator.TEST", "tags.1", "bar"),
resource.TestCheckResourceAttr("jetstream_operator.TEST", "expiry", "2100-02-11T00:00:00Z"),
),
},
},
Expand Down

0 comments on commit 8fbc9e7

Please sign in to comment.