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: Use managed account from the SDK #2420

Merged
merged 2 commits into from
Jan 25, 2024
Merged
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
115 changes: 68 additions & 47 deletions pkg/resources/managed_account.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package resources

import (
"context"
"database/sql"
"errors"
"fmt"
"log"
"time"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake"
snowflakeValidation "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand All @@ -17,13 +18,6 @@ const (
SnowflakeReaderAccountType = "READER"
)

var managedAccountProperties = []string{
"admin_name",
"admin_password",
"type",
"comment",
}

var managedAccountSchema = map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -102,82 +96,109 @@ func ManagedAccount() *schema.Resource {

// CreateManagedAccount implements schema.CreateFunc.
func CreateManagedAccount(d *schema.ResourceData, meta interface{}) error {
return CreateResource(
"this does not seem to be used",
managedAccountProperties,
managedAccountSchema,
snowflake.NewManagedAccountBuilder,
initialReadManagedAccount,
)(d, meta)
}
db := meta.(*sql.DB)
ctx := context.Background()
client := sdk.NewClientFromDB(db)

name := d.Get("name").(string)
id := sdk.NewAccountObjectIdentifier(name)

adminName := d.Get("admin_name").(string)
adminPassword := d.Get("admin_password").(string)
createParams := sdk.NewCreateManagedAccountParamsRequest(adminName, adminPassword)

if v, ok := d.GetOk("comment"); ok {
createParams.WithComment(sdk.String(v.(string)))
}

createRequest := sdk.NewCreateManagedAccountRequest(id, *createParams)

err := client.ManagedAccounts.Create(ctx, createRequest)
if err != nil {
return err
}

d.SetId(helpers.EncodeSnowflakeID(id))

// initialReadManagedAccount is used for the first read, since the locator takes
// some time to appear. This is currently implemented as a sleep. @TODO actually
// wait until the locator is generated.
func initialReadManagedAccount(d *schema.ResourceData, meta interface{}) error {
log.Println("[INFO] sleeping to give the locator a chance to be generated")
// lintignore:R018
time.Sleep(10 * time.Second)
return ReadManagedAccount(d, meta)
}

// ReadManagedAccount implements schema.ReadFunc.
func ReadManagedAccount(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
id := d.Id()

stmt := snowflake.NewManagedAccountBuilder(id).Show()
row := snowflake.QueryRow(db, stmt)
a, err := snowflake.ScanManagedAccount(row)

if errors.Is(err, sql.ErrNoRows) {
// If not found, remove resource from
log.Printf("[DEBUG] managed account (%s) not found", d.Id())
d.SetId("")
return nil
}
client := sdk.NewClientFromDB(db)

ctx := context.Background()
objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier)

// We have to wait during the first read, since the locator takes some time to appear.
// This approach has a downside of not handling correctly the situation where managed account was removed externally.
// TODO [SNOW-1003380]: discuss it as a provider-wide topic during resources redesign.
var managedAccount *sdk.ManagedAccount
var err error
sfc-gh-jcieslak marked this conversation as resolved.
Show resolved Hide resolved
err = helpers.Retry(5, 3*time.Second, func() (error, bool) {
managedAccount, err = client.ManagedAccounts.ShowByID(ctx, objectIdentifier)
if err != nil {
return nil, false
}
return nil, true
})
if err != nil {
return err
}

if err := d.Set("name", a.Name.String); err != nil {
if err := d.Set("name", managedAccount.Name); err != nil {
return err
}

if err := d.Set("cloud", a.Cloud.String); err != nil {
if err := d.Set("cloud", managedAccount.Cloud); err != nil {
return err
}

if err := d.Set("region", a.Region.String); err != nil {
if err := d.Set("region", managedAccount.Region); err != nil {
return err
}

if err := d.Set("locator", a.Locator.String); err != nil {
if err := d.Set("locator", managedAccount.Locator); err != nil {
return err
}

if err := d.Set("created_on", a.CreatedOn.String); err != nil {
if err := d.Set("created_on", managedAccount.CreatedOn); err != nil {
return err
}

if err := d.Set("url", a.URL.String); err != nil {
if err := d.Set("url", managedAccount.URL); err != nil {
return err
}

if a.IsReader {
if managedAccount.IsReader {
if err := d.Set("type", "READER"); err != nil {
return err
}
} else {
return fmt.Errorf("unable to determine the account type")
}

err = d.Set("comment", a.Comment.String)
if err := d.Set("comment", managedAccount.Comment); err != nil {
return err
}

return err
return nil
}

// DeleteManagedAccount implements schema.DeleteFunc.
func DeleteManagedAccount(d *schema.ResourceData, meta interface{}) error {
return DeleteResource("this does not seem to be used", snowflake.NewManagedAccountBuilder)(d, meta)
db := meta.(*sql.DB)
client := sdk.NewClientFromDB(db)
ctx := context.Background()

objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier)

err := client.ManagedAccounts.Drop(ctx, sdk.NewDropManagedAccountRequest(objectIdentifier))
if err != nil {
return err
}

d.SetId("")
return nil
}
64 changes: 0 additions & 64 deletions pkg/resources/managed_account_test.go

This file was deleted.

114 changes: 0 additions & 114 deletions pkg/resources/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,125 +3,11 @@ package resources
import (
"database/sql"
"fmt"
"log"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func CreateResource(
t string,
properties []string,
s map[string]*schema.Schema,
builder func(string) *snowflake.Builder,
read func(*schema.ResourceData, interface{}) error,
) func(*schema.ResourceData, interface{}) error {
return func(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
name := d.Get("name").(string)

qb := builder(name).Create()

for _, field := range properties {
val, ok := d.GetOk(field)
if ok {
switch s[field].Type {
case schema.TypeString:
valStr := val.(string)
qb.SetString(field, valStr)
case schema.TypeBool:
valBool := val.(bool)
qb.SetBool(field, valBool)
case schema.TypeInt:
valInt := val.(int)
qb.SetInt(field, valInt)
case schema.TypeSet:
valList := expandStringList(val.(*schema.Set).List())
qb.SetStringList(field, valList)
}
}
}
if v, ok := d.GetOk("tag"); ok {
tags := getTags(v)
qb.SetTags(tags.toSnowflakeTagValues())
}
if err := snowflake.Exec(db, qb.Statement()); err != nil {
return fmt.Errorf("error creating %s err = %w", t, err)
}

d.SetId(name)

return read(d, meta)
}
}

func UpdateResource(
t string,
properties []string,
s map[string]*schema.Schema,
builder func(string) *snowflake.Builder,
read func(*schema.ResourceData, interface{}) error,
) func(*schema.ResourceData, interface{}) error {
return func(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
if d.HasChange("name") {
// I wish this could be done on one line.
oldNameI, newNameI := d.GetChange("name")
oldName := oldNameI.(string)
newName := newNameI.(string)

stmt := builder(oldName).Rename(newName)

err := snowflake.Exec(db, stmt)
if err != nil {
return fmt.Errorf("error renaming %s %s to %s err = %w", t, oldName, newName, err)
}
d.SetId(newName)
}

changes := []string{}
for _, prop := range properties {
if d.HasChange(prop) {
changes = append(changes, prop)
}
}
if len(changes) > 0 {
name := d.Get("name").(string)
qb := builder(name).Alter()

for _, field := range changes {
val := d.Get(field)
switch s[field].Type {
case schema.TypeString:
valStr := val.(string)
qb.SetString(field, valStr)
case schema.TypeBool:
valBool := val.(bool)
qb.SetBool(field, valBool)
case schema.TypeInt:
valInt := val.(int)
qb.SetInt(field, valInt)
case schema.TypeSet:
valList := expandStringList(val.(*schema.Set).List())
qb.SetStringList(field, valList)
}
}
if d.HasChange("tag") {
log.Println("[DEBUG] updating tags")
v := d.Get("tag")
tags := getTags(v)
qb.SetTags(tags.toSnowflakeTagValues())
}

if err := snowflake.Exec(db, qb.Statement()); err != nil {
return fmt.Errorf("error altering %s err = %w", t, err)
}
}
log.Println("[DEBUG] performing read")
return read(d, meta)
}
}

func DeleteResource(t string, builder func(string) *snowflake.Builder) func(*schema.ResourceData, interface{}) error {
return func(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
Expand Down
Loading
Loading