From f133ceb35029cda4c6e47eb6788ac479e605fcbf Mon Sep 17 00:00:00 2001 From: Dejan Golja Date: Sun, 24 May 2015 17:27:02 +1000 Subject: [PATCH 1/2] Added support for SHOW GRANTS FOR USER syntax --- CHANGELOG.md | 28 ++++------------------------ influxql/ast.go | 22 ++++++++++++++++++++++ influxql/parser.go | 24 +++++++++++++++++++++++- influxql/token.go | 2 ++ meta/data.go | 10 ++++++++++ meta/statement_executor.go | 16 ++++++++++++++++ meta/store.go | 9 +++++++++ 7 files changed, 86 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac3077b6ab3..06c205d72ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## v0.9.1 [unreleased] +### Features + +- [2650](https://github.com/influxdb/influxdb/pull/2650): Add SHOW GRANTS FOR USER statement. Thanks @n1tr0g + ### Bugfixes - [#2908](https://github.com/influxdb/influxdb/issues/2908): Field mismatch error messages need to be updated @@ -51,30 +55,6 @@ - [2865](https://github.com/influxdb/influxdb/pull/2865) -- Return an empty set of results if database does not exist in shard metadata. ### Features -- [2858](https://github.com/influxdb/influxdb/pull/2858): Support setting openTSDB write consistency. - -## v0.9.0-rc32 [2015-06-07] - -### Release Notes - -This released introduced an updated write path and clustering design. The data format has also changed, so you'll need to wipe out your data to upgrade from RC31. There should be no other data changes before v0.9.0 is released. - -### Features -- [#1997](https://github.com/influxdb/influxdb/pull/1997): Update SELECT * to return tag values. -- [#2599](https://github.com/influxdb/influxdb/issues/2599): Add "epoch" URL param and return JSON time values as epoch instead of date strings. -- [#2682](https://github.com/influxdb/influxdb/issues/2682): Adding pr checklist to CONTRIBUTING.md -- [#2683](https://github.com/influxdb/influxdb/issues/2683): Add batching support to Graphite inputs. -- [#2687](https://github.com/influxdb/influxdb/issues/2687): Add batching support to Collectd inputs. -- [#2696](https://github.com/influxdb/influxdb/pull/2696): Add line protocol. This is now the preferred way to write data. -- [#2751](https://github.com/influxdb/influxdb/pull/2751): Add UDP input. UDP only supports the line protocol now. -- [#2684](https://github.com/influxdb/influxdb/pull/2684): Include client timeout configuration. Thanks @vladlopes! - -### Bugfixes -- [#2776](https://github.com/influxdb/influxdb/issues/2776): Re-implement retention policy enforcement. -- [#2635](https://github.com/influxdb/influxdb/issues/2635): Fix querying against boolean field in WHERE clause. -- [#2644](https://github.com/influxdb/influxdb/issues/2644): Make SHOW queries work with FROM //. -- [#2501](https://github.com/influxdb/influxdb/issues/2501): Name the FlagSet for the shell and add a version flag. Thanks @neonstalwart -- [#2647](https://github.com/influxdb/influxdb/issues/2647): Fixes typos in sample config file - thanks @claws! ## v0.9.0-rc31 [2015-05-21] diff --git a/influxql/ast.go b/influxql/ast.go index 7c4549b4769..938e548c52c 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -93,6 +93,7 @@ func (*DropSeriesStatement) node() {} func (*DropUserStatement) node() {} func (*GrantStatement) node() {} func (*ShowContinuousQueriesStatement) node() {} +func (*ShowGrantsForUserStatement) node() {} func (*ShowServersStatement) node() {} func (*ShowDatabasesStatement) node() {} func (*ShowFieldKeysStatement) node() {} @@ -193,6 +194,7 @@ func (*DropSeriesStatement) stmt() {} func (*DropUserStatement) stmt() {} func (*GrantStatement) stmt() {} func (*ShowContinuousQueriesStatement) stmt() {} +func (*ShowGrantsForUserStatement) stmt() {} func (*ShowServersStatement) stmt() {} func (*ShowDatabasesStatement) stmt() {} func (*ShowFieldKeysStatement) stmt() {} @@ -1518,6 +1520,26 @@ func (s *ShowContinuousQueriesStatement) RequiredPrivileges() ExecutionPrivilege return ExecutionPrivileges{{Name: "", Privilege: ReadPrivilege}} } +// ShowGrantsForUserStatement represents a command for listing user privileges. +type ShowGrantsForUserStatement struct { + // Name of the user to display privileges. + Name string +} + +// String returns a string representation of the show grants for user. +func (s *ShowGrantsForUserStatement) String() string { + var buf bytes.Buffer + _, _ = buf.WriteString("SHOW GRANTS FOR ") + _, _ = buf.WriteString(s.Name) + + return buf.String() +} + +// RequiredPrivileges returns the privilege required to execute a ShowGrantsForUserStatement +func (s *ShowGrantsForUserStatement) RequiredPrivileges() ExecutionPrivileges { + return ExecutionPrivileges{{Name: "", Privilege: AllPrivileges}} +} + // ShowServersStatement represents a command for listing all servers. type ShowServersStatement struct{} diff --git a/influxql/parser.go b/influxql/parser.go index 03e5a729633..d7e1415afe1 100644 --- a/influxql/parser.go +++ b/influxql/parser.go @@ -107,6 +107,8 @@ func (p *Parser) parseShowStatement() (Statement, error) { switch tok { case CONTINUOUS: return p.parseShowContinuousQueriesStatement() + case GRANTS: + return p.parseGrantsForUserStatement() case DATABASES: return p.parseShowDatabasesStatement() case SERVERS: @@ -143,7 +145,7 @@ func (p *Parser) parseShowStatement() (Statement, error) { return p.parseShowUsersStatement() } - return nil, newParseError(tokstr(tok, lit), []string{"CONTINUOUS", "DATABASES", "FIELD", "MEASUREMENTS", "RETENTION", "SERIES", "SERVERS", "TAG", "USERS"}, pos) + return nil, newParseError(tokstr(tok, lit), []string{"CONTINUOUS", "DATABASES", "FIELD", "GRANTS", "MEASUREMENTS", "RETENTION", "SERIES", "SERVERS", "TAG", "USERS"}, pos) } // parseCreateStatement parses a string and returns a create statement. @@ -1081,6 +1083,26 @@ func (p *Parser) parseShowServersStatement() (*ShowServersStatement, error) { return stmt, nil } +// parseGrantsForUserStatement parses a string and returns a ShowGrantsForUserStatement. +// This function assumes the "SHOW GRANTS" tokens have already been consumed. +func (p *Parser) parseGrantsForUserStatement() (*ShowGrantsForUserStatement, error) { + stmt := &ShowGrantsForUserStatement{} + + // Expect a "FOR" token. + if tok, pos, lit := p.scanIgnoreWhitespace(); tok != FOR { + return nil, newParseError(tokstr(tok, lit), []string{"FOR"}, pos) + } + + // Parse the name of the user to be displayed. + lit, err := p.parseIdent() + if err != nil { + return nil, err + } + stmt.Name = lit + + return stmt, nil +} + // parseShowDatabasesStatement parses a string and returns a ShowDatabasesStatement. // This function assumes the "SHOW DATABASE" tokens have already been consumed. func (p *Parser) parseShowDatabasesStatement() (*ShowDatabasesStatement, error) { diff --git a/influxql/token.go b/influxql/token.go index 4eae37c7221..0eb5b7a9a6d 100644 --- a/influxql/token.go +++ b/influxql/token.go @@ -78,6 +78,7 @@ const ( FOR FROM GRANT + GRANTS GROUP IF IN @@ -184,6 +185,7 @@ var tokens = [...]string{ FOR: "FOR", FROM: "FROM", GRANT: "GRANT", + GRANTS: "GRANTS", GROUP: "GROUP", IF: "IF", IN: "IN", diff --git a/meta/data.go b/meta/data.go index a2ec2160923..97ebf490f37 100644 --- a/meta/data.go +++ b/meta/data.go @@ -458,6 +458,16 @@ func (data *Data) SetPrivilege(name, database string, p influxql.Privilege) erro return nil } +// UserPrivileges get privileges for a user. +func (data *Data) UserPrivileges(name string) (map[string]influxql.Privilege, error) { + ui := data.User(name) + if ui == nil { + return nil, ErrUserNotFound + } + + return ui.Privileges, nil +} + // Clone returns a copy of data with a new version. func (data *Data) Clone() *Data { other := *data diff --git a/meta/statement_executor.go b/meta/statement_executor.go index 211e6a5eb6b..3e21763f55f 100644 --- a/meta/statement_executor.go +++ b/meta/statement_executor.go @@ -27,6 +27,7 @@ type StatementExecutor struct { UpdateUser(name, password string) error DropUser(name string) error SetPrivilege(username, database string, p influxql.Privilege) error + UserPrivileges(username string) (map[string]influxql.Privilege, error) CreateContinuousQuery(database, name, query string) error DropContinuousQuery(database, name string) error @@ -42,6 +43,8 @@ func (e *StatementExecutor) ExecuteStatement(stmt influxql.Statement) *influxql. return e.executeDropDatabaseStatement(stmt) case *influxql.ShowDatabasesStatement: return e.executeShowDatabasesStatement(stmt) + case *influxql.ShowGrantsForUserStatement: + return e.executeShowGrantsForUserStatement(stmt) case *influxql.ShowServersStatement: return e.executeShowServersStatement(stmt) case *influxql.CreateUserStatement: @@ -97,6 +100,19 @@ func (e *StatementExecutor) executeShowDatabasesStatement(q *influxql.ShowDataba return &influxql.Result{Series: []*influxql.Row{row}} } +func (e *StatementExecutor) executeShowGrantsForUserStatement(q *influxql.ShowGrantsForUserStatement) *influxql.Result { + priv, err := e.Store.UserPrivileges(q.Name) + if err != nil { + return &influxql.Result{Err: err} + } + + row := &influxql.Row{Columns: []string{"database", "privilege"}} + for d, p := range priv { + row.Values = append(row.Values, []interface{}{d, p.String()}) + } + return &influxql.Result{Series: []*influxql.Row{row}} +} + func (e *StatementExecutor) executeShowServersStatement(q *influxql.ShowServersStatement) *influxql.Result { nis, err := e.Store.Nodes() if err != nil { diff --git a/meta/store.go b/meta/store.go index c0a5e0fc29a..52a585ac41d 100644 --- a/meta/store.go +++ b/meta/store.go @@ -1039,6 +1039,15 @@ func (s *Store) SetPrivilege(username, database string, p influxql.Privilege) er ) } +// UserPrivileges returns a list of all databases. +func (s *Store) UserPrivileges(username string) (p map[string]influxql.Privilege, err error) { + err = s.read(func(data *Data) error { + p, err = data.UserPrivileges(username) + return err + }) + return +} + // UserCount returns the number of users defined in the cluster. func (s *Store) UserCount() (count int, err error) { err = s.read(func(data *Data) error { From 000d6b8b0b8d5729b48d89a6c34c16e77f84b6d0 Mon Sep 17 00:00:00 2001 From: Dejan Golja Date: Sun, 24 May 2015 23:02:42 +1000 Subject: [PATCH 2/2] added tests for SHOW GRANTS FOR statements --- CHANGELOG.md | 26 +++++++++++++++++++++++++- influxql/parser_test.go | 10 +++++++++- meta/statement_executor_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c205d72ee..21d189a39e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features -- [2650](https://github.com/influxdb/influxdb/pull/2650): Add SHOW GRANTS FOR USER statement. Thanks @n1tr0g +- [2650](https://github.com/influxdb/influxdb/pull/2650): Add SHOW GRANTS FOR USER statement. Thanks @n1tr0g. ### Bugfixes @@ -55,6 +55,30 @@ - [2865](https://github.com/influxdb/influxdb/pull/2865) -- Return an empty set of results if database does not exist in shard metadata. ### Features +- [2858](https://github.com/influxdb/influxdb/pull/2858): Support setting openTSDB write consistency. + +## v0.9.0-rc32 [2015-06-07] + +### Release Notes + +This released introduced an updated write path and clustering design. The data format has also changed, so you'll need to wipe out your data to upgrade from RC31. There should be no other data changes before v0.9.0 is released. + +### Features +- [#1997](https://github.com/influxdb/influxdb/pull/1997): Update SELECT * to return tag values. +- [#2599](https://github.com/influxdb/influxdb/issues/2599): Add "epoch" URL param and return JSON time values as epoch instead of date strings. +- [#2682](https://github.com/influxdb/influxdb/issues/2682): Adding pr checklist to CONTRIBUTING.md +- [#2683](https://github.com/influxdb/influxdb/issues/2683): Add batching support to Graphite inputs. +- [#2687](https://github.com/influxdb/influxdb/issues/2687): Add batching support to Collectd inputs. +- [#2696](https://github.com/influxdb/influxdb/pull/2696): Add line protocol. This is now the preferred way to write data. +- [#2751](https://github.com/influxdb/influxdb/pull/2751): Add UDP input. UDP only supports the line protocol now. +- [#2684](https://github.com/influxdb/influxdb/pull/2684): Include client timeout configuration. Thanks @vladlopes! + +### Bugfixes +- [#2776](https://github.com/influxdb/influxdb/issues/2776): Re-implement retention policy enforcement. +- [#2635](https://github.com/influxdb/influxdb/issues/2635): Fix querying against boolean field in WHERE clause. +- [#2644](https://github.com/influxdb/influxdb/issues/2644): Make SHOW queries work with FROM //. +- [#2501](https://github.com/influxdb/influxdb/issues/2501): Name the FlagSet for the shell and add a version flag. Thanks @neonstalwart +- [#2647](https://github.com/influxdb/influxdb/issues/2647): Fixes typos in sample config file - thanks @claws! ## v0.9.0-rc31 [2015-05-21] diff --git a/influxql/parser_test.go b/influxql/parser_test.go index 4d111dfe72d..0f3425fe9e1 100644 --- a/influxql/parser_test.go +++ b/influxql/parser_test.go @@ -534,6 +534,12 @@ func TestParser_ParseStatement(t *testing.T) { stmt: &influxql.ShowServersStatement{}, }, + // SHOW GRANTS + { + s: `SHOW GRANTS FOR jdoe`, + stmt: &influxql.ShowGrantsForUserStatement{Name: "jdoe"}, + }, + // SHOW DATABASES { s: `SHOW DATABASES`, @@ -1228,8 +1234,10 @@ func TestParser_ParseStatement(t *testing.T) { {s: `SHOW CONTINUOUS`, err: `found EOF, expected QUERIES at line 1, char 17`}, {s: `SHOW RETENTION`, err: `found EOF, expected POLICIES at line 1, char 16`}, {s: `SHOW RETENTION POLICIES`, err: `found EOF, expected identifier at line 1, char 25`}, - {s: `SHOW FOO`, err: `found FOO, expected CONTINUOUS, DATABASES, FIELD, MEASUREMENTS, RETENTION, SERIES, SERVERS, TAG, USERS at line 1, char 6`}, + {s: `SHOW FOO`, err: `found FOO, expected CONTINUOUS, DATABASES, FIELD, GRANTS, MEASUREMENTS, RETENTION, SERIES, SERVERS, TAG, USERS at line 1, char 6`}, {s: `SHOW STATS ON`, err: `found EOF, expected string at line 1, char 15`}, + {s: `SHOW GRANTS`, err: `found EOF, expected FOR at line 1, char 13`}, + {s: `SHOW GRANTS FOR`, err: `found EOF, expected identifier at line 1, char 17`}, {s: `DROP CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 17`}, {s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier at line 1, char 23`}, {s: `DROP CONTINUOUS QUERY myquery`, err: `found EOF, expected ON at line 1, char 31`}, diff --git a/meta/statement_executor_test.go b/meta/statement_executor_test.go index 6de0b754a7a..f2a6fc0d124 100644 --- a/meta/statement_executor_test.go +++ b/meta/statement_executor_test.go @@ -83,6 +83,34 @@ func TestStatementExecutor_ExecuteStatement_ShowDatabases_Err(t *testing.T) { } } +// Ensure a SHOW GRANTS FOR statement can be executed. +func TestStatementExecutor_ExecuteStatement_ShowGrantsFor(t *testing.T) { + e := NewStatementExecutor() + e.Store.UserPrivilegesFn = func(username string) (map[string]influxql.Privilege, error) { + if username != "dejan" { + t.Fatalf("unexpected username: %s", username) + } + return map[string]influxql.Privilege{ + "dejan": influxql.ReadPrivilege, + "golja": influxql.WritePrivilege, + }, nil + } + + if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW GRANTS FOR dejan`)); res.Err != nil { + t.Fatal(res.Err) + } else if !reflect.DeepEqual(res.Series, influxql.Rows{ + { + Columns: []string{"database", "privilege"}, + Values: [][]interface{}{ + {"dejan", "READ"}, + {"golja", "WRITE"}, + }, + }, + }) { + t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) + } +} + // Ensure a SHOW SERVERS statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowServers(t *testing.T) { e := NewStatementExecutor() @@ -701,6 +729,7 @@ type StatementExecutorStore struct { UpdateUserFn func(name, password string) error DropUserFn func(name string) error SetPrivilegeFn func(username, database string, p influxql.Privilege) error + UserPrivilegesFn func(username string) (map[string]influxql.Privilege, error) ContinuousQueriesFn func() ([]meta.ContinuousQueryInfo, error) CreateContinuousQueryFn func(database, name, query string) error DropContinuousQueryFn func(database, name string) error @@ -766,6 +795,10 @@ func (s *StatementExecutorStore) SetPrivilege(username, database string, p influ return s.SetPrivilegeFn(username, database, p) } +func (s *StatementExecutorStore) UserPrivileges(username string) (map[string]influxql.Privilege, error) { + return s.UserPrivilegesFn(username) +} + func (s *StatementExecutorStore) ContinuousQueries() ([]meta.ContinuousQueryInfo, error) { return s.ContinuousQueriesFn() }