github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/influxdb/resource_user.go (about)

     1  package influxdb
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/terraform/helper/schema"
     8  	"github.com/influxdata/influxdb/client"
     9  )
    10  
    11  func resourceUser() *schema.Resource {
    12  	return &schema.Resource{
    13  		Create: createUser,
    14  		Read:   readUser,
    15  		Update: updateUser,
    16  		Delete: deleteUser,
    17  
    18  		Schema: map[string]*schema.Schema{
    19  			"name": &schema.Schema{
    20  				Type:     schema.TypeString,
    21  				Required: true,
    22  				ForceNew: true,
    23  			},
    24  			"password": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  			"admin": &schema.Schema{
    30  				Type:     schema.TypeBool,
    31  				Optional: true,
    32  				Computed: true,
    33  			},
    34  			"grant": &schema.Schema{
    35  				Type:     schema.TypeList,
    36  				Optional: true,
    37  				Elem: &schema.Resource{
    38  					Schema: map[string]*schema.Schema{
    39  						"database": &schema.Schema{
    40  							Type:     schema.TypeString,
    41  							Required: true,
    42  						},
    43  						"privilege": &schema.Schema{
    44  							Type:     schema.TypeString,
    45  							Required: true,
    46  						},
    47  					},
    48  				},
    49  			},
    50  		},
    51  	}
    52  }
    53  
    54  func createUser(d *schema.ResourceData, meta interface{}) error {
    55  	conn := meta.(*client.Client)
    56  
    57  	name := d.Get("name").(string)
    58  	password := d.Get("password").(string)
    59  
    60  	is_admin := d.Get("admin").(bool)
    61  	admin_privileges := ""
    62  	if is_admin {
    63  		admin_privileges = "WITH ALL PRIVILEGES"
    64  	}
    65  
    66  	queryStr := fmt.Sprintf("CREATE USER %s WITH PASSWORD '%s' %s", name, password, admin_privileges)
    67  	query := client.Query{
    68  		Command: queryStr,
    69  	}
    70  
    71  	resp, err := conn.Query(query)
    72  	if err != nil {
    73  		return err
    74  	}
    75  	if resp.Err != nil {
    76  		return resp.Err
    77  	}
    78  
    79  	d.SetId(fmt.Sprintf("influxdb-user:%s", name))
    80  
    81  	if v, ok := d.GetOk("grant"); ok {
    82  		grants := v.([]interface{})
    83  		for _, vv := range grants {
    84  			grant := vv.(map[string]interface{})
    85  			if err := grantPrivilegeOn(conn, grant["privilege"].(string), grant["database"].(string), name); err != nil {
    86  				return err
    87  			}
    88  		}
    89  	}
    90  
    91  	return readUser(d, meta)
    92  }
    93  
    94  func exec(conn *client.Client, query string) error {
    95  	resp, err := conn.Query(client.Query{
    96  		Command: query,
    97  	})
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if resp.Err != nil {
   102  		return resp.Err
   103  	}
   104  	return nil
   105  }
   106  
   107  func grantPrivilegeOn(conn *client.Client, privilege, database, user string) error {
   108  	return exec(conn, fmt.Sprintf("GRANT %s ON %s TO %s", privilege, quoteIdentifier(database), user))
   109  }
   110  
   111  func revokePrivilegeOn(conn *client.Client, privilege, database, user string) error {
   112  	return exec(conn, fmt.Sprintf("REVOKE %s ON %s FROM %s", privilege, quoteIdentifier(database), user))
   113  }
   114  
   115  func grantAllOn(conn *client.Client, user string) error {
   116  	return exec(conn, fmt.Sprintf("GRANT ALL PRIVILEGES TO %s", user))
   117  }
   118  
   119  func revokeAllOn(conn *client.Client, user string) error {
   120  	return exec(conn, fmt.Sprintf("REVOKE ALL PRIVILEGES FROM %s", user))
   121  }
   122  
   123  func readUser(d *schema.ResourceData, meta interface{}) error {
   124  	conn := meta.(*client.Client)
   125  	name := d.Get("name").(string)
   126  
   127  	// InfluxDB doesn't have a command to check the existence of a single
   128  	// User, so we instead must read the list of all Users and see
   129  	// if ours is present in it.
   130  	query := client.Query{
   131  		Command: "SHOW USERS",
   132  	}
   133  
   134  	resp, err := conn.Query(query)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	if resp.Err != nil {
   139  		return resp.Err
   140  	}
   141  
   142  	var found = false
   143  	for _, result := range resp.Results[0].Series[0].Values {
   144  		if result[0] == name {
   145  			found = true
   146  			d.Set("admin", result[1].(bool))
   147  			break
   148  		}
   149  	}
   150  
   151  	if !found {
   152  		// If we fell out here then we didn't find our User in the list.
   153  		d.SetId("")
   154  
   155  		return nil
   156  	}
   157  
   158  	return readGrants(d, meta)
   159  }
   160  
   161  func readGrants(d *schema.ResourceData, meta interface{}) error {
   162  	conn := meta.(*client.Client)
   163  	name := d.Get("name").(string)
   164  
   165  	query := client.Query{
   166  		Command: fmt.Sprintf("SHOW GRANTS FOR %s", name),
   167  	}
   168  
   169  	resp, err := conn.Query(query)
   170  	if err != nil {
   171  		return err
   172  	}
   173  
   174  	if resp.Err != nil {
   175  		return resp.Err
   176  	}
   177  
   178  	var grants = []map[string]string{}
   179  	for _, result := range resp.Results[0].Series[0].Values {
   180  		if result[1].(string) != "NO PRIVILEGES" {
   181  			var grant = map[string]string{
   182  				"database":  result[0].(string),
   183  				"privilege": strings.ToLower(result[1].(string)),
   184  			}
   185  			grants = append(grants, grant)
   186  		}
   187  	}
   188  	d.Set("grant", grants)
   189  	return nil
   190  }
   191  
   192  func updateUser(d *schema.ResourceData, meta interface{}) error {
   193  	conn := meta.(*client.Client)
   194  	name := d.Get("name").(string)
   195  
   196  	if d.HasChange("admin") {
   197  		if !d.Get("admin").(bool) {
   198  			revokeAllOn(conn, name)
   199  		} else {
   200  			grantAllOn(conn, name)
   201  		}
   202  	}
   203  
   204  	if d.HasChange("grant") {
   205  		oldGrantV, newGrantV := d.GetChange("grant")
   206  		oldGrant := oldGrantV.([]interface{})
   207  		newGrant := newGrantV.([]interface{})
   208  
   209  		for _, oGV := range oldGrant {
   210  			oldGrant := oGV.(map[string]interface{})
   211  
   212  			exists := false
   213  			privilege := oldGrant["privilege"].(string)
   214  			for _, nGV := range newGrant {
   215  				newGrant := nGV.(map[string]interface{})
   216  
   217  				if newGrant["database"].(string) == oldGrant["database"].(string) {
   218  					exists = true
   219  					privilege = newGrant["privilege"].(string)
   220  				}
   221  			}
   222  
   223  			if !exists {
   224  				revokePrivilegeOn(conn, oldGrant["privilege"].(string), oldGrant["database"].(string), name)
   225  			} else {
   226  				if privilege != oldGrant["privilege"].(string) {
   227  					grantPrivilegeOn(conn, privilege, oldGrant["database"].(string), name)
   228  				}
   229  			}
   230  		}
   231  
   232  		for _, nGV := range newGrant {
   233  			newGrant := nGV.(map[string]interface{})
   234  
   235  			exists := false
   236  			for _, oGV := range oldGrant {
   237  				oldGrant := oGV.(map[string]interface{})
   238  
   239  				exists = exists || (newGrant["database"].(string) == oldGrant["database"].(string) && newGrant["privilege"].(string) == oldGrant["privilege"].(string))
   240  			}
   241  
   242  			if !exists {
   243  				grantPrivilegeOn(conn, newGrant["privilege"].(string), newGrant["database"].(string), name)
   244  			}
   245  		}
   246  	}
   247  
   248  	return readUser(d, meta)
   249  }
   250  
   251  func deleteUser(d *schema.ResourceData, meta interface{}) error {
   252  	conn := meta.(*client.Client)
   253  	name := d.Get("name").(string)
   254  
   255  	queryStr := fmt.Sprintf("DROP USER %s", name)
   256  	query := client.Query{
   257  		Command: queryStr,
   258  	}
   259  
   260  	resp, err := conn.Query(query)
   261  	if err != nil {
   262  		return err
   263  	}
   264  	if resp.Err != nil {
   265  		return resp.Err
   266  	}
   267  
   268  	d.SetId("")
   269  
   270  	return nil
   271  }