Skip to content

Commit

Permalink
feat: Adding users datasource (#1013)
Browse files Browse the repository at this point in the history
* add news users datasource

* fix typo in description

* generate docs again with new rules
  • Loading branch information
FrancisLfg authored May 24, 2022
1 parent 72c3180 commit 4cd86e4
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 0 deletions.
51 changes: 51 additions & 0 deletions docs/data-sources/users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "snowflake_users Data Source - terraform-provider-snowflake"
subcategory: ""
description: |-
---

# snowflake_users (Data Source)



## Example Usage

```terraform
data "snowflake_users" "current" {
pattern = "user1"
}
```

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

### Required

- `pattern` (String) Users pattern for which to return metadata. Please refer to LIKE keyword from snowflake documentation : https://docs.snowflake.com/en/sql-reference/sql/show-users.html#parameters

### Read-Only

- `id` (String) The ID of this resource.
- `users` (List of Object) The users in the database (see [below for nested schema](#nestedatt--users))

<a id="nestedatt--users"></a>
### Nested Schema for `users`

Read-Only:

- `comment` (String)
- `default_namespace` (String)
- `default_role` (String)
- `default_warehouse` (String)
- `disabled` (Boolean)
- `display_name` (String)
- `email` (String)
- `first_name` (String)
- `has_rsa_public_key` (Boolean)
- `last_name` (String)
- `login_name` (String)
- `name` (String)


3 changes: 3 additions & 0 deletions examples/data-sources/snowflake_users/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "snowflake_users" "current" {
pattern = "user1"
}
145 changes: 145 additions & 0 deletions pkg/datasources/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package datasources

import (
"database/sql"
"fmt"
"log"

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

var usersSchema = map[string]*schema.Schema{
"pattern": {
Type: schema.TypeString,
Required: true,
Description: "Users pattern for which to return metadata. Please refer to LIKE keyword from " +
"snowflake documentation : https://docs.snowflake.com/en/sql-reference/sql/show-users.html#parameters",
},
"users": {
Type: schema.TypeList,
Computed: true,
Description: "The users in the database",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
"login_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"comment": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"disabled": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"default_warehouse": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"default_namespace": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"default_role": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"has_rsa_public_key": {
Type: schema.TypeBool,
Computed: true,
},
"email": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"display_name": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"first_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"last_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
},
},
}

func Users() *schema.Resource {
return &schema.Resource{
Read: ReadUsers,
Schema: usersSchema,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
}
}

func ReadUsers(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
userPattern := d.Get("pattern").(string)

account, err := snowflake.ReadCurrentAccount(db)
if err != nil {
log.Print("[DEBUG] unable to retrieve current account")
d.SetId("")
return nil
}

d.SetId(fmt.Sprintf("%s.%s", account.Account, account.Region))

currentUsers, err := snowflake.ListUsers(userPattern, db)
if err == sql.ErrNoRows {
// If not found, mark resource to be removed from statefile during apply or refresh
log.Printf("[DEBUG] no users found in account (%s)", d.Id())
d.SetId("")
return nil
} else if err != nil {
log.Printf("[DEBUG] unable to parse users in account (%s)", d.Id())
d.SetId("")
return nil
}

users := []map[string]interface{}{}

for _, user := range currentUsers {
userMap := map[string]interface{}{}

userMap["name"] = user.Name.String
userMap["login_name"] = user.LoginName.String
userMap["comment"] = user.Comment.String
userMap["disabled"] = user.Disabled
userMap["default_warehouse"] = user.DefaultWarehouse.String
userMap["default_namespace"] = user.DefaultNamespace.String
userMap["default_role"] = user.DefaultRole.String
userMap["has_rsa_public_key"] = user.HasRsaPublicKey
userMap["email"] = user.Email.String
userMap["display_name"] = user.DisplayName.String
userMap["first_name"] = user.FirstName.String
userMap["last_name"] = user.LastName.String

users = append(users, userMap)
}

return d.Set("users", users)
}
51 changes: 51 additions & 0 deletions pkg/datasources/users_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package datasources_test

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccUsers(t *testing.T) {
userName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
resource.ParallelTest(t, resource.TestCase{
Providers: providers(),
Steps: []resource.TestStep{
{
Config: users(userName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.snowflake_users.u", "users.#"),
resource.TestCheckResourceAttr("data.snowflake_users.u", "users.#", "1"),
resource.TestCheckResourceAttr("data.snowflake_users.u", "users.0.name", userName),
resource.TestCheckResourceAttr("data.snowflake_users.u", "users.0.disabled", "false"),
),
},
},
})
}

func users(userName string) string {
return fmt.Sprintf(`
resource "snowflake_user" "u" {
name = "%s"
comment = "test comment"
login_name = "%s_login"
display_name = "Display Name"
first_name = "Alex"
last_name = "Kita"
email = "[email protected]"
disabled = false
default_warehouse="foo"
default_role="foo"
default_namespace="foo"
}
data snowflake_users "u" {
pattern = "%s"
depends_on = [snowflake_user.u]
}
`, userName, userName, userName)
}
1 change: 1 addition & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ func getDataSources() map[string]*schema.Resource {
"snowflake_databases": datasources.Databases(),
"snowflake_database": datasources.Database(),
"snowflake_role": datasources.Role(),
"snowflake_users": datasources.Users(),
}

return dataSources
Expand Down
21 changes: 21 additions & 0 deletions pkg/snowflake/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package snowflake

import (
"database/sql"
"fmt"
"log"

"github.com/pkg/errors"

"github.com/jmoiron/sqlx"
)
Expand Down Expand Up @@ -88,3 +92,20 @@ type DescribeUserProp struct {
Property string `db:"property"`
Value sql.NullString `db:"value"`
}

func ListUsers(pattern string, db *sql.DB) ([]user, error) {
stmt := fmt.Sprintf(`SHOW USERS like '%s'`, pattern)
rows, err := Query(db, stmt)
if err != nil {
return nil, err
}
defer rows.Close()

dbs := []user{}
err = sqlx.StructScan(rows, &dbs)
if err == sql.ErrNoRows {
log.Printf("[DEBUG] no users found")
return nil, nil
}
return dbs, errors.Wrapf(err, "unable to scan row for %s", stmt)
}

0 comments on commit 4cd86e4

Please sign in to comment.