2015-05-28 04:06:09 +00:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
2015-08-24 19:29:17 +00:00
|
|
|
"bytes"
|
2015-05-28 04:06:09 +00:00
|
|
|
"fmt"
|
2015-08-24 19:29:17 +00:00
|
|
|
"strconv"
|
|
|
|
"time"
|
2015-05-28 04:06:09 +00:00
|
|
|
|
|
|
|
"github.com/influxdb/influxdb/influxql"
|
|
|
|
)
|
|
|
|
|
|
|
|
// StatementExecutor translates InfluxQL queries to meta store methods.
|
|
|
|
type StatementExecutor struct {
|
|
|
|
Store interface {
|
|
|
|
Nodes() ([]NodeInfo, error)
|
2015-07-27 21:13:03 +00:00
|
|
|
Peers() ([]string, error)
|
2015-05-28 04:06:09 +00:00
|
|
|
|
|
|
|
Database(name string) (*DatabaseInfo, error)
|
|
|
|
Databases() ([]DatabaseInfo, error)
|
|
|
|
CreateDatabase(name string) (*DatabaseInfo, error)
|
|
|
|
DropDatabase(name string) error
|
|
|
|
|
|
|
|
DefaultRetentionPolicy(database string) (*RetentionPolicyInfo, error)
|
|
|
|
CreateRetentionPolicy(database string, rpi *RetentionPolicyInfo) (*RetentionPolicyInfo, error)
|
|
|
|
UpdateRetentionPolicy(database, name string, rpu *RetentionPolicyUpdate) error
|
|
|
|
SetDefaultRetentionPolicy(database, name string) error
|
|
|
|
DropRetentionPolicy(database, name string) error
|
|
|
|
|
|
|
|
Users() ([]UserInfo, error)
|
|
|
|
CreateUser(name, password string, admin bool) (*UserInfo, error)
|
|
|
|
UpdateUser(name, password string) error
|
|
|
|
DropUser(name string) error
|
|
|
|
SetPrivilege(username, database string, p influxql.Privilege) error
|
2015-07-10 20:39:33 +00:00
|
|
|
SetAdminPrivilege(username string, admin bool) error
|
2015-05-24 07:27:02 +00:00
|
|
|
UserPrivileges(username string) (map[string]influxql.Privilege, error)
|
2015-07-10 20:39:33 +00:00
|
|
|
UserPrivilege(username, database string) (*influxql.Privilege, error)
|
2015-05-28 04:06:09 +00:00
|
|
|
|
|
|
|
CreateContinuousQuery(database, name, query string) error
|
|
|
|
DropContinuousQuery(database, name string) error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExecuteStatement executes stmt against the meta store as user.
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) ExecuteStatement(stmt influxql.Statement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
switch stmt := stmt.(type) {
|
|
|
|
case *influxql.CreateDatabaseStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeCreateDatabaseStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.DropDatabaseStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeDropDatabaseStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.ShowDatabasesStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeShowDatabasesStatement(stmt)
|
2015-05-24 07:27:02 +00:00
|
|
|
case *influxql.ShowGrantsForUserStatement:
|
|
|
|
return e.executeShowGrantsForUserStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.ShowServersStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeShowServersStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.CreateUserStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeCreateUserStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.SetPasswordUserStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeSetPasswordUserStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.DropUserStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeDropUserStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.ShowUsersStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeShowUsersStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.GrantStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeGrantStatement(stmt)
|
2015-07-10 20:39:33 +00:00
|
|
|
case *influxql.GrantAdminStatement:
|
|
|
|
return e.executeGrantAdminStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.RevokeStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeRevokeStatement(stmt)
|
2015-07-10 20:39:33 +00:00
|
|
|
case *influxql.RevokeAdminStatement:
|
|
|
|
return e.executeRevokeAdminStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.CreateRetentionPolicyStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeCreateRetentionPolicyStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.AlterRetentionPolicyStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeAlterRetentionPolicyStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.DropRetentionPolicyStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeDropRetentionPolicyStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.ShowRetentionPoliciesStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeShowRetentionPoliciesStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.CreateContinuousQueryStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeCreateContinuousQueryStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.DropContinuousQueryStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeDropContinuousQueryStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
case *influxql.ShowContinuousQueriesStatement:
|
2015-05-30 20:00:46 +00:00
|
|
|
return e.executeShowContinuousQueriesStatement(stmt)
|
2015-08-24 19:29:17 +00:00
|
|
|
case *influxql.ShowShardsStatement:
|
|
|
|
return e.executeShowShardsStatement(stmt)
|
|
|
|
case *influxql.ShowStatsStatement:
|
|
|
|
return e.executeShowStatsStatement(stmt)
|
2015-05-28 04:06:09 +00:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unsupported statement type: %T", stmt))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeCreateDatabaseStatement(q *influxql.CreateDatabaseStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
_, err := e.Store.CreateDatabase(q.Name)
|
2015-08-29 00:42:12 +00:00
|
|
|
if err == ErrDatabaseExists && q.IfNotExists {
|
|
|
|
err = nil
|
|
|
|
}
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeDropDatabaseStatement(q *influxql.DropDatabaseStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: e.Store.DropDatabase(q.Name)}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeShowDatabasesStatement(q *influxql.ShowDatabasesStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
dis, err := e.Store.Databases()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
row := &influxql.Row{Name: "databases", Columns: []string{"name"}}
|
|
|
|
for _, di := range dis {
|
|
|
|
row.Values = append(row.Values, []interface{}{di.Name})
|
|
|
|
}
|
|
|
|
return &influxql.Result{Series: []*influxql.Row{row}}
|
|
|
|
}
|
|
|
|
|
2015-05-24 07:27:02 +00:00
|
|
|
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}}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeShowServersStatement(q *influxql.ShowServersStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
nis, err := e.Store.Nodes()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-07-27 21:13:03 +00:00
|
|
|
peers, err := e.Store.Peers()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-08-05 16:04:24 +00:00
|
|
|
row := &influxql.Row{Columns: []string{"id", "cluster_addr", "raft"}}
|
2015-05-28 04:06:09 +00:00
|
|
|
for _, ni := range nis {
|
2015-08-05 16:04:24 +00:00
|
|
|
row.Values = append(row.Values, []interface{}{ni.ID, ni.Host, contains(peers, ni.Host)})
|
2015-05-28 04:06:09 +00:00
|
|
|
}
|
|
|
|
return &influxql.Result{Series: []*influxql.Row{row}}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeCreateUserStatement(q *influxql.CreateUserStatement) *influxql.Result {
|
2015-07-10 20:39:33 +00:00
|
|
|
_, err := e.Store.CreateUser(q.Name, q.Password, q.Admin)
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeSetPasswordUserStatement(q *influxql.SetPasswordUserStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: e.Store.UpdateUser(q.Name, q.Password)}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeDropUserStatement(q *influxql.DropUserStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: e.Store.DropUser(q.Name)}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeShowUsersStatement(q *influxql.ShowUsersStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
uis, err := e.Store.Users()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
row := &influxql.Row{Columns: []string{"user", "admin"}}
|
2015-05-30 20:00:46 +00:00
|
|
|
for _, ui := range uis {
|
|
|
|
row.Values = append(row.Values, []interface{}{ui.Name, ui.Admin})
|
2015-05-28 04:06:09 +00:00
|
|
|
}
|
|
|
|
return &influxql.Result{Series: []*influxql.Row{row}}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeGrantStatement(stmt *influxql.GrantStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: e.Store.SetPrivilege(stmt.User, stmt.On, stmt.Privilege)}
|
|
|
|
}
|
|
|
|
|
2015-07-10 20:39:33 +00:00
|
|
|
func (e *StatementExecutor) executeGrantAdminStatement(stmt *influxql.GrantAdminStatement) *influxql.Result {
|
|
|
|
return &influxql.Result{Err: e.Store.SetAdminPrivilege(stmt.User, true)}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeRevokeStatement(stmt *influxql.RevokeStatement) *influxql.Result {
|
2015-07-10 20:39:33 +00:00
|
|
|
priv := influxql.NoPrivileges
|
|
|
|
|
|
|
|
// Revoking all privileges means there's no need to look at existing user privileges.
|
|
|
|
if stmt.Privilege != influxql.AllPrivileges {
|
|
|
|
p, err := e.Store.UserPrivilege(stmt.User, stmt.On)
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
// Bit clear (AND NOT) the user's privilege with the revoked privilege.
|
|
|
|
priv = *p &^ stmt.Privilege
|
|
|
|
}
|
|
|
|
|
|
|
|
return &influxql.Result{Err: e.Store.SetPrivilege(stmt.User, stmt.On, priv)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *StatementExecutor) executeRevokeAdminStatement(stmt *influxql.RevokeAdminStatement) *influxql.Result {
|
|
|
|
return &influxql.Result{Err: e.Store.SetAdminPrivilege(stmt.User, false)}
|
2015-05-28 04:06:09 +00:00
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeCreateRetentionPolicyStatement(stmt *influxql.CreateRetentionPolicyStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
rpi := NewRetentionPolicyInfo(stmt.Name)
|
|
|
|
rpi.Duration = stmt.Duration
|
|
|
|
rpi.ReplicaN = stmt.Replication
|
|
|
|
|
|
|
|
// Create new retention policy.
|
|
|
|
_, err := e.Store.CreateRetentionPolicy(stmt.Database, rpi)
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If requested, set new policy as the default.
|
|
|
|
if stmt.Default {
|
|
|
|
err = e.Store.SetDefaultRetentionPolicy(stmt.Database, stmt.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeAlterRetentionPolicyStatement(stmt *influxql.AlterRetentionPolicyStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
rpu := &RetentionPolicyUpdate{
|
|
|
|
Duration: stmt.Duration,
|
|
|
|
ReplicaN: stmt.Replication,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the retention policy.
|
|
|
|
err := e.Store.UpdateRetentionPolicy(stmt.Database, stmt.Name, rpu)
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If requested, set as default retention policy.
|
|
|
|
if stmt.Default {
|
|
|
|
err = e.Store.SetDefaultRetentionPolicy(stmt.Database, stmt.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeDropRetentionPolicyStatement(q *influxql.DropRetentionPolicyStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{Err: e.Store.DropRetentionPolicy(q.Database, q.Name)}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeShowRetentionPoliciesStatement(q *influxql.ShowRetentionPoliciesStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
di, err := e.Store.Database(q.Database)
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
} else if di == nil {
|
|
|
|
return &influxql.Result{Err: ErrDatabaseNotFound}
|
|
|
|
}
|
|
|
|
|
|
|
|
row := &influxql.Row{Columns: []string{"name", "duration", "replicaN", "default"}}
|
|
|
|
for _, rpi := range di.RetentionPolicies {
|
|
|
|
row.Values = append(row.Values, []interface{}{rpi.Name, rpi.Duration.String(), rpi.ReplicaN, di.DefaultRetentionPolicy == rpi.Name})
|
|
|
|
}
|
|
|
|
return &influxql.Result{Series: []*influxql.Row{row}}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeCreateContinuousQueryStatement(q *influxql.CreateContinuousQueryStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{
|
2015-06-15 12:55:27 +00:00
|
|
|
Err: e.Store.CreateContinuousQuery(q.Database, q.Name, q.String()),
|
2015-05-28 04:06:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeDropContinuousQueryStatement(q *influxql.DropContinuousQueryStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
return &influxql.Result{
|
|
|
|
Err: e.Store.DropContinuousQuery(q.Database, q.Name),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 20:00:46 +00:00
|
|
|
func (e *StatementExecutor) executeShowContinuousQueriesStatement(stmt *influxql.ShowContinuousQueriesStatement) *influxql.Result {
|
2015-05-28 04:06:09 +00:00
|
|
|
dis, err := e.Store.Databases()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
rows := []*influxql.Row{}
|
|
|
|
for _, di := range dis {
|
|
|
|
row := &influxql.Row{Columns: []string{"name", "query"}, Name: di.Name}
|
|
|
|
for _, cqi := range di.ContinuousQueries {
|
|
|
|
row.Values = append(row.Values, []interface{}{cqi.Name, cqi.Query})
|
|
|
|
}
|
|
|
|
rows = append(rows, row)
|
|
|
|
}
|
|
|
|
return &influxql.Result{Series: rows}
|
|
|
|
}
|
2015-08-24 19:29:17 +00:00
|
|
|
|
|
|
|
func (e *StatementExecutor) executeShowShardsStatement(stmt *influxql.ShowShardsStatement) *influxql.Result {
|
|
|
|
dis, err := e.Store.Databases()
|
|
|
|
if err != nil {
|
|
|
|
return &influxql.Result{Err: err}
|
|
|
|
}
|
|
|
|
|
|
|
|
rows := []*influxql.Row{}
|
|
|
|
for _, di := range dis {
|
|
|
|
row := &influxql.Row{Columns: []string{"id", "start_time", "end_time", "expiry_time", "owners"}, Name: di.Name}
|
|
|
|
for _, rpi := range di.RetentionPolicies {
|
|
|
|
for _, sgi := range rpi.ShardGroups {
|
|
|
|
for _, si := range sgi.Shards {
|
|
|
|
ownerIDs := make([]uint64, len(si.Owners))
|
|
|
|
for i, owner := range si.Owners {
|
|
|
|
ownerIDs[i] = owner.NodeID
|
|
|
|
}
|
|
|
|
|
|
|
|
row.Values = append(row.Values, []interface{}{
|
|
|
|
si.ID,
|
|
|
|
sgi.StartTime.UTC().Format(time.RFC3339),
|
|
|
|
sgi.EndTime.UTC().Format(time.RFC3339),
|
|
|
|
sgi.EndTime.Add(rpi.Duration).UTC().Format(time.RFC3339),
|
|
|
|
joinUint64(ownerIDs),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rows = append(rows, row)
|
|
|
|
}
|
|
|
|
return &influxql.Result{Series: rows}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *StatementExecutor) executeShowStatsStatement(stmt *influxql.ShowStatsStatement) *influxql.Result {
|
|
|
|
return &influxql.Result{Err: fmt.Errorf("SHOW STATS is not implemented yet")}
|
|
|
|
}
|
|
|
|
|
|
|
|
// joinUint64 returns a comma-delimited string of uint64 numbers.
|
|
|
|
func joinUint64(a []uint64) string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
for i, x := range a {
|
|
|
|
buf.WriteString(strconv.FormatUint(x, 10))
|
|
|
|
if i < len(a)-1 {
|
|
|
|
buf.WriteRune(',')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buf.String()
|
|
|
|
}
|