1
0
mirror of https://github.com/Oxalide/vsphere-influxdb-go.git synced 2023-10-10 11:36:51 +00:00

add vendoring with go dep

This commit is contained in:
Adrian Todorov
2017-10-25 20:52:40 +00:00
parent 704f4d20d1
commit a59409f16b
1627 changed files with 489673 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
package meta
import (
"errors"
"time"
"github.com/influxdata/influxdb/monitor/diagnostics"
)
const (
// DefaultLeaseDuration is the default duration for leases.
DefaultLeaseDuration = 60 * time.Second
// DefaultLoggingEnabled determines if log messages are printed for the meta service.
DefaultLoggingEnabled = true
)
// Config represents the meta configuration.
type Config struct {
Dir string `toml:"dir"`
RetentionAutoCreate bool `toml:"retention-autocreate"`
LoggingEnabled bool `toml:"logging-enabled"`
}
// NewConfig builds a new configuration with default values.
func NewConfig() *Config {
return &Config{
RetentionAutoCreate: true,
LoggingEnabled: DefaultLoggingEnabled,
}
}
// Validate returns an error if the config is invalid.
func (c *Config) Validate() error {
if c.Dir == "" {
return errors.New("Meta.Dir must be specified")
}
return nil
}
// Diagnostics returns a diagnostics representation of a subset of the Config.
func (c *Config) Diagnostics() (*diagnostics.Diagnostics, error) {
return diagnostics.RowFromMap(map[string]interface{}{
"dir": c.Dir,
}), nil
}

View File

@@ -0,0 +1,26 @@
package meta_test
import (
"testing"
"github.com/BurntSushi/toml"
"github.com/influxdata/influxdb/services/meta"
)
func TestConfig_Parse(t *testing.T) {
// Parse configuration.
var c meta.Config
if _, err := toml.Decode(`
dir = "/tmp/foo"
logging-enabled = false
`, &c); err != nil {
t.Fatal(err)
}
// Validate configuration.
if c.Dir != "/tmp/foo" {
t.Fatalf("unexpected dir: %s", c.Dir)
} else if c.LoggingEnabled {
t.Fatalf("unexpected logging enabled: %v", c.LoggingEnabled)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
package meta
import (
"sort"
"time"
"testing"
)
func TestShardGroupSort(t *testing.T) {
sg1 := ShardGroupInfo{
ID: 1,
StartTime: time.Unix(1000, 0),
EndTime: time.Unix(1100, 0),
TruncatedAt: time.Unix(1050, 0),
}
sg2 := ShardGroupInfo{
ID: 2,
StartTime: time.Unix(1000, 0),
EndTime: time.Unix(1100, 0),
}
sgs := ShardGroupInfos{sg2, sg1}
sort.Sort(sgs)
if sgs[len(sgs)-1].ID != 2 {
t.Fatal("unstable sort for ShardGroupInfos")
}
}
func Test_Data_RetentionPolicy_MarshalBinary(t *testing.T) {
zeroTime := time.Time{}
epoch := time.Unix(0, 0).UTC()
startTime := zeroTime
sgi := &ShardGroupInfo{
StartTime: startTime,
}
isgi := sgi.marshal()
sgi.unmarshal(isgi)
if got, exp := sgi.StartTime.UTC(), epoch.UTC(); got != exp {
t.Errorf("unexpected start time. got: %s, exp: %s", got, exp)
}
startTime = time.Unix(0, 0)
endTime := startTime.Add(time.Hour * 24)
sgi = &ShardGroupInfo{
StartTime: startTime,
EndTime: endTime,
}
isgi = sgi.marshal()
sgi.unmarshal(isgi)
if got, exp := sgi.StartTime.UTC(), startTime.UTC(); got != exp {
t.Errorf("unexpected start time. got: %s, exp: %s", got, exp)
}
if got, exp := sgi.EndTime.UTC(), endTime.UTC(); got != exp {
t.Errorf("unexpected end time. got: %s, exp: %s", got, exp)
}
if got, exp := sgi.DeletedAt.UTC(), zeroTime.UTC(); got != exp {
t.Errorf("unexpected DeletedAt time. got: %s, exp: %s", got, exp)
}
}

View File

@@ -0,0 +1,204 @@
package meta_test
import (
"reflect"
"testing"
"time"
"github.com/influxdata/influxdb/influxql"
"github.com/influxdata/influxdb/services/meta"
)
func Test_Data_DropDatabase(t *testing.T) {
data := &meta.Data{
Databases: []meta.DatabaseInfo{
{Name: "db0"},
{Name: "db1"},
{Name: "db2"},
{Name: "db4"},
{Name: "db5"},
},
Users: []meta.UserInfo{
{Name: "user1", Privileges: map[string]influxql.Privilege{"db1": influxql.ReadPrivilege, "db2": influxql.ReadPrivilege}},
{Name: "user2", Privileges: map[string]influxql.Privilege{"db2": influxql.ReadPrivilege}},
},
}
// Dropping the first database removes it from the Data object.
expDbs := make([]meta.DatabaseInfo, 4)
copy(expDbs, data.Databases[1:])
if err := data.DropDatabase("db0"); err != nil {
t.Fatal(err)
} else if got, exp := data.Databases, expDbs; !reflect.DeepEqual(got, exp) {
t.Fatalf("got %v, expected %v", got, exp)
}
// Dropping a middle database removes it from the data object.
expDbs = []meta.DatabaseInfo{{Name: "db1"}, {Name: "db2"}, {Name: "db5"}}
if err := data.DropDatabase("db4"); err != nil {
t.Fatal(err)
} else if got, exp := data.Databases, expDbs; !reflect.DeepEqual(got, exp) {
t.Fatalf("got %v, expected %v", got, exp)
}
// Dropping the last database removes it from the data object.
expDbs = []meta.DatabaseInfo{{Name: "db1"}, {Name: "db2"}}
if err := data.DropDatabase("db5"); err != nil {
t.Fatal(err)
} else if got, exp := data.Databases, expDbs; !reflect.DeepEqual(got, exp) {
t.Fatalf("got %v, expected %v", got, exp)
}
// Dropping a database also drops all the user privileges associated with
// it.
expUsers := []meta.UserInfo{
{Name: "user1", Privileges: map[string]influxql.Privilege{"db1": influxql.ReadPrivilege}},
{Name: "user2", Privileges: map[string]influxql.Privilege{}},
}
if err := data.DropDatabase("db2"); err != nil {
t.Fatal(err)
} else if got, exp := data.Users, expUsers; !reflect.DeepEqual(got, exp) {
t.Fatalf("got %v, expected %v", got, exp)
}
}
func Test_Data_CreateRetentionPolicy(t *testing.T) {
data := meta.Data{}
err := data.CreateDatabase("foo")
if err != nil {
t.Fatal(err)
}
err = data.CreateRetentionPolicy("foo", &meta.RetentionPolicyInfo{
Name: "bar",
ReplicaN: 1,
Duration: 24 * time.Hour,
}, false)
if err != nil {
t.Fatal(err)
}
rp, err := data.RetentionPolicy("foo", "bar")
if err != nil {
t.Fatal(err)
}
if rp == nil {
t.Fatal("creation of retention policy failed")
}
// Try to recreate the same RP with default set to true, should fail
err = data.CreateRetentionPolicy("foo", &meta.RetentionPolicyInfo{
Name: "bar",
ReplicaN: 1,
Duration: 24 * time.Hour,
}, true)
if err == nil || err != meta.ErrRetentionPolicyConflict {
t.Fatalf("unexpected error. got: %v, exp: %s", err, meta.ErrRetentionPolicyConflict)
}
// Creating the same RP with the same specifications should succeed
err = data.CreateRetentionPolicy("foo", &meta.RetentionPolicyInfo{
Name: "bar",
ReplicaN: 1,
Duration: 24 * time.Hour,
}, false)
if err != nil {
t.Fatal(err)
}
}
func TestData_AdminUserExists(t *testing.T) {
data := meta.Data{}
// No users means no admin.
if data.AdminUserExists() {
t.Fatal("no admin user should exist")
}
// Add a non-admin user.
if err := data.CreateUser("user1", "a", false); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), false; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Add an admin user.
if err := data.CreateUser("admin1", "a", true); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), true; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Remove the original user
if err := data.DropUser("user1"); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), true; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Add another admin
if err := data.CreateUser("admin2", "a", true); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), true; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Revoke privileges of the first admin
if err := data.SetAdminPrivilege("admin1", false); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), true; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Add user1 back.
if err := data.CreateUser("user1", "a", false); err != nil {
t.Fatal(err)
}
// Revoke remaining admin.
if err := data.SetAdminPrivilege("admin2", false); err != nil {
t.Fatal(err)
}
// No longer any admins
if got, exp := data.AdminUserExists(), false; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Make user1 an admin
if err := data.SetAdminPrivilege("user1", true); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), true; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
// Drop user1...
if err := data.DropUser("user1"); err != nil {
t.Fatal(err)
}
if got, exp := data.AdminUserExists(), false; got != exp {
t.Fatalf("got %v, expected %v", got, exp)
}
}
func TestUserInfo_AuthorizeDatabase(t *testing.T) {
emptyUser := &meta.UserInfo{}
if !emptyUser.AuthorizeDatabase(influxql.NoPrivileges, "anydb") {
t.Fatal("expected NoPrivileges to be authorized but it wasn't")
}
if emptyUser.AuthorizeDatabase(influxql.ReadPrivilege, "anydb") {
t.Fatal("expected ReadPrivilege to prevent authorization, but it was authorized")
}
adminUser := &meta.UserInfo{Admin: true}
if !adminUser.AuthorizeDatabase(influxql.AllPrivileges, "anydb") {
t.Fatalf("expected admin to be authorized but it wasn't")
}
}

View File

@@ -0,0 +1,115 @@
package meta
import (
"errors"
"fmt"
)
var (
// ErrStoreOpen is returned when opening an already open store.
ErrStoreOpen = errors.New("store already open")
// ErrStoreClosed is returned when closing an already closed store.
ErrStoreClosed = errors.New("raft store already closed")
)
var (
// ErrDatabaseExists is returned when creating an already existing database.
ErrDatabaseExists = errors.New("database already exists")
// ErrDatabaseNotExists is returned when operating on a not existing database.
ErrDatabaseNotExists = errors.New("database does not exist")
// ErrDatabaseNameRequired is returned when creating a database without a name.
ErrDatabaseNameRequired = errors.New("database name required")
// ErrInvalidName is returned when attempting to create a database or retention policy with an invalid name
ErrInvalidName = errors.New("invalid name")
)
var (
// ErrRetentionPolicyExists is returned when creating an already existing policy.
ErrRetentionPolicyExists = errors.New("retention policy already exists")
// ErrRetentionPolicyNotFound is returned when an expected policy wasn't found.
ErrRetentionPolicyNotFound = errors.New("retention policy not found")
// ErrRetentionPolicyDefault is returned when attempting a prohibited operation
// on a default retention policy.
ErrRetentionPolicyDefault = errors.New("retention policy is default")
// ErrRetentionPolicyRequired is returned when a retention policy is required
// by an operation, but a nil policy was passed.
ErrRetentionPolicyRequired = errors.New("retention policy required")
// ErrRetentionPolicyNameRequired is returned when creating a policy without a name.
ErrRetentionPolicyNameRequired = errors.New("retention policy name required")
// ErrRetentionPolicyNameExists is returned when renaming a policy to
// the same name as another existing policy.
ErrRetentionPolicyNameExists = errors.New("retention policy name already exists")
// ErrRetentionPolicyDurationTooLow is returned when updating a retention
// policy that has a duration lower than the allowed minimum.
ErrRetentionPolicyDurationTooLow = fmt.Errorf("retention policy duration must be at least %s", MinRetentionPolicyDuration)
// ErrRetentionPolicyConflict is returned when creating a retention policy conflicts
// with an existing policy.
ErrRetentionPolicyConflict = errors.New("retention policy conflicts with an existing policy")
// ErrIncompatibleDurations is returned when creating or updating a
// retention policy that has a duration lower than the current shard
// duration.
ErrIncompatibleDurations = errors.New("retention policy duration must be greater than the shard duration")
// ErrReplicationFactorTooLow is returned when the replication factor is not in an
// acceptable range.
ErrReplicationFactorTooLow = errors.New("replication factor must be greater than 0")
)
var (
// ErrShardGroupExists is returned when creating an already existing shard group.
ErrShardGroupExists = errors.New("shard group already exists")
// ErrShardGroupNotFound is returned when mutating a shard group that doesn't exist.
ErrShardGroupNotFound = errors.New("shard group not found")
// ErrShardNotReplicated is returned if the node requested to be dropped has
// the last copy of a shard present and the force keyword was not used
ErrShardNotReplicated = errors.New("shard not replicated")
)
var (
// ErrContinuousQueryExists is returned when creating an already existing continuous query.
ErrContinuousQueryExists = errors.New("continuous query already exists")
// ErrContinuousQueryNotFound is returned when removing a continuous query that doesn't exist.
ErrContinuousQueryNotFound = errors.New("continuous query not found")
)
var (
// ErrSubscriptionExists is returned when creating an already existing subscription.
ErrSubscriptionExists = errors.New("subscription already exists")
// ErrSubscriptionNotFound is returned when removing a subscription that doesn't exist.
ErrSubscriptionNotFound = errors.New("subscription not found")
)
// ErrInvalidSubscriptionURL is returned when the subscription's destination URL is invalid.
func ErrInvalidSubscriptionURL(url string) error {
return fmt.Errorf("invalid subscription URL: %s", url)
}
var (
// ErrUserExists is returned when creating an already existing user.
ErrUserExists = errors.New("user already exists")
// ErrUserNotFound is returned when mutating a user that doesn't exist.
ErrUserNotFound = errors.New("user not found")
// ErrUsernameRequired is returned when creating a user without a username.
ErrUsernameRequired = errors.New("username required")
// ErrAuthenticate is returned when authentication fails.
ErrAuthenticate = errors.New("authentication failed")
)

View File

@@ -0,0 +1,10 @@
// +build !windows
package meta
import "os"
// renameFile will rename the source to target using os function.
func renameFile(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}

View File

@@ -0,0 +1,14 @@
package meta
import "os"
// renameFile will rename the source to target using os function. If target exists it will be removed before renaming.
func renameFile(oldpath, newpath string) error {
if _, err := os.Stat(newpath); err == nil {
if err = os.Remove(newpath); nil != err {
return err
}
}
return os.Rename(oldpath, newpath)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,393 @@
package meta;
//========================================================================
//
// Metadata
//
//========================================================================
message Data {
required uint64 Term = 1;
required uint64 Index = 2;
required uint64 ClusterID = 3;
repeated NodeInfo Nodes = 4;
repeated DatabaseInfo Databases = 5;
repeated UserInfo Users = 6;
required uint64 MaxNodeID = 7;
required uint64 MaxShardGroupID = 8;
required uint64 MaxShardID = 9;
// added for 0.10.0
repeated NodeInfo DataNodes = 10;
repeated NodeInfo MetaNodes = 11;
}
message NodeInfo {
required uint64 ID = 1;
required string Host = 2;
optional string TCPHost = 3;
}
message DatabaseInfo {
required string Name = 1;
required string DefaultRetentionPolicy = 2;
repeated RetentionPolicyInfo RetentionPolicies = 3;
repeated ContinuousQueryInfo ContinuousQueries = 4;
}
message RetentionPolicySpec {
optional string Name = 1;
optional int64 Duration = 2;
optional int64 ShardGroupDuration = 3;
optional uint32 ReplicaN = 4;
}
message RetentionPolicyInfo {
required string Name = 1;
required int64 Duration = 2;
required int64 ShardGroupDuration = 3;
required uint32 ReplicaN = 4;
repeated ShardGroupInfo ShardGroups = 5;
repeated SubscriptionInfo Subscriptions = 6;
}
message ShardGroupInfo {
required uint64 ID = 1;
required int64 StartTime = 2;
required int64 EndTime = 3;
required int64 DeletedAt = 4;
repeated ShardInfo Shards = 5;
optional int64 TruncatedAt = 6;
}
message ShardInfo {
required uint64 ID = 1;
repeated uint64 OwnerIDs = 2 [deprecated=true];
repeated ShardOwner Owners = 3;
}
message SubscriptionInfo{
required string Name = 1;
required string Mode = 2;
repeated string Destinations = 3;
}
message ShardOwner {
required uint64 NodeID = 1;
}
message ContinuousQueryInfo {
required string Name = 1;
required string Query = 2;
}
message UserInfo {
required string Name = 1;
required string Hash = 2;
required bool Admin = 3;
repeated UserPrivilege Privileges = 4;
}
message UserPrivilege {
required string Database = 1;
required int32 Privilege = 2;
}
//========================================================================
//
// COMMANDS
//
//========================================================================
message Command {
extensions 100 to max;
enum Type {
CreateNodeCommand = 1;
DeleteNodeCommand = 2;
CreateDatabaseCommand = 3;
DropDatabaseCommand = 4;
CreateRetentionPolicyCommand = 5;
DropRetentionPolicyCommand = 6;
SetDefaultRetentionPolicyCommand = 7;
UpdateRetentionPolicyCommand = 8;
CreateShardGroupCommand = 9;
DeleteShardGroupCommand = 10;
CreateContinuousQueryCommand = 11;
DropContinuousQueryCommand = 12;
CreateUserCommand = 13;
DropUserCommand = 14;
UpdateUserCommand = 15;
SetPrivilegeCommand = 16;
SetDataCommand = 17;
SetAdminPrivilegeCommand = 18;
UpdateNodeCommand = 19;
CreateSubscriptionCommand = 21;
DropSubscriptionCommand = 22;
RemovePeerCommand = 23;
CreateMetaNodeCommand = 24;
CreateDataNodeCommand = 25;
UpdateDataNodeCommand = 26;
DeleteMetaNodeCommand = 27;
DeleteDataNodeCommand = 28;
SetMetaNodeCommand = 29;
DropShardCommand = 30;
}
required Type type = 1;
}
// This isn't used in >= 0.10.0. Kept around for upgrade purposes. Instead
// look at CreateDataNodeCommand and CreateMetaNodeCommand
message CreateNodeCommand {
extend Command {
optional CreateNodeCommand command = 101;
}
required string Host = 1;
required uint64 Rand = 2;
}
message DeleteNodeCommand {
extend Command {
optional DeleteNodeCommand command = 102;
}
required uint64 ID = 1;
required bool Force = 2;
}
message CreateDatabaseCommand {
extend Command {
optional CreateDatabaseCommand command = 103;
}
required string Name = 1;
optional RetentionPolicyInfo RetentionPolicy = 2;
}
message DropDatabaseCommand {
extend Command {
optional DropDatabaseCommand command = 104;
}
required string Name = 1;
}
message CreateRetentionPolicyCommand {
extend Command {
optional CreateRetentionPolicyCommand command = 105;
}
required string Database = 1;
required RetentionPolicyInfo RetentionPolicy = 2;
}
message DropRetentionPolicyCommand {
extend Command {
optional DropRetentionPolicyCommand command = 106;
}
required string Database = 1;
required string Name = 2;
}
message SetDefaultRetentionPolicyCommand {
extend Command {
optional SetDefaultRetentionPolicyCommand command = 107;
}
required string Database = 1;
required string Name = 2;
}
message UpdateRetentionPolicyCommand {
extend Command {
optional UpdateRetentionPolicyCommand command = 108;
}
required string Database = 1;
required string Name = 2;
optional string NewName = 3;
optional int64 Duration = 4;
optional uint32 ReplicaN = 5;
}
message CreateShardGroupCommand {
extend Command {
optional CreateShardGroupCommand command = 109;
}
required string Database = 1;
required string Policy = 2;
required int64 Timestamp = 3;
}
message DeleteShardGroupCommand {
extend Command {
optional DeleteShardGroupCommand command = 110;
}
required string Database = 1;
required string Policy = 2;
required uint64 ShardGroupID = 3;
}
message CreateContinuousQueryCommand {
extend Command {
optional CreateContinuousQueryCommand command = 111;
}
required string Database = 1;
required string Name = 2;
required string Query = 3;
}
message DropContinuousQueryCommand {
extend Command {
optional DropContinuousQueryCommand command = 112;
}
required string Database = 1;
required string Name = 2;
}
message CreateUserCommand {
extend Command {
optional CreateUserCommand command = 113;
}
required string Name = 1;
required string Hash = 2;
required bool Admin = 3;
}
message DropUserCommand {
extend Command {
optional DropUserCommand command = 114;
}
required string Name = 1;
}
message UpdateUserCommand {
extend Command {
optional UpdateUserCommand command = 115;
}
required string Name = 1;
required string Hash = 2;
}
message SetPrivilegeCommand {
extend Command {
optional SetPrivilegeCommand command = 116;
}
required string Username = 1;
required string Database = 2;
required int32 Privilege = 3;
}
message SetDataCommand {
extend Command {
optional SetDataCommand command = 117;
}
required Data Data = 1;
}
message SetAdminPrivilegeCommand {
extend Command {
optional SetAdminPrivilegeCommand command = 118;
}
required string Username = 1;
required bool Admin = 2;
}
message UpdateNodeCommand {
extend Command {
optional UpdateNodeCommand command = 119;
}
required uint64 ID = 1;
required string Host = 2;
}
message CreateSubscriptionCommand {
extend Command {
optional CreateSubscriptionCommand command = 121;
}
required string Name = 1;
required string Database = 2;
required string RetentionPolicy = 3;
required string Mode = 4;
repeated string Destinations = 5;
}
message DropSubscriptionCommand {
extend Command {
optional DropSubscriptionCommand command = 122;
}
required string Name = 1;
required string Database = 2;
required string RetentionPolicy = 3;
}
message RemovePeerCommand {
extend Command {
optional RemovePeerCommand command = 123;
}
optional uint64 ID = 1;
required string Addr = 2;
}
message CreateMetaNodeCommand {
extend Command {
optional CreateMetaNodeCommand command = 124;
}
required string HTTPAddr = 1;
required string TCPAddr = 2;
required uint64 Rand = 3;
}
message CreateDataNodeCommand {
extend Command {
optional CreateDataNodeCommand command = 125;
}
required string HTTPAddr = 1;
required string TCPAddr = 2;
}
message UpdateDataNodeCommand {
extend Command {
optional UpdateDataNodeCommand command = 126;
}
required uint64 ID = 1;
required string Host = 2;
required string TCPHost = 3;
}
message DeleteMetaNodeCommand {
extend Command {
optional DeleteMetaNodeCommand command = 127;
}
required uint64 ID = 1;
}
message DeleteDataNodeCommand {
extend Command {
optional DeleteDataNodeCommand command = 128;
}
required uint64 ID = 1;
}
message Response {
required bool OK = 1;
optional string Error = 2;
optional uint64 Index = 3;
}
// SetMetaNodeCommand is for the initial metanode in a cluster or
// if the single host restarts and its hostname changes, this will update it
message SetMetaNodeCommand {
extend Command {
optional SetMetaNodeCommand command = 129;
}
required string HTTPAddr = 1;
required string TCPAddr = 2;
required uint64 Rand = 3;
}
message DropShardCommand {
extend Command {
optional DropShardCommand command = 130;
}
required uint64 ID = 1;
}

View File

@@ -0,0 +1,7 @@
package meta
import "golang.org/x/crypto/bcrypt"
func init() {
bcryptCost = bcrypt.MinCost
}

View File

@@ -0,0 +1,117 @@
package meta
import (
"fmt"
"github.com/influxdata/influxdb/influxql"
)
// QueryAuthorizer determines whether a user is authorized to execute a given query.
type QueryAuthorizer struct {
Client *Client
}
// NewQueryAuthorizer returns a new instance of QueryAuthorizer.
func NewQueryAuthorizer(c *Client) *QueryAuthorizer {
return &QueryAuthorizer{
Client: c,
}
}
// AuthorizeQuery authorizes u to execute q on database.
// Database can be "" for queries that do not require a database.
// If no user is provided it will return an error unless the query's first statement is to create
// a root user.
func (a *QueryAuthorizer) AuthorizeQuery(u User, query *influxql.Query, database string) error {
// Special case if no users exist.
if n := a.Client.UserCount(); n == 0 {
// Ensure there is at least one statement.
if len(query.Statements) > 0 {
// First statement in the query must create a user with admin privilege.
cu, ok := query.Statements[0].(*influxql.CreateUserStatement)
if ok && cu.Admin == true {
return nil
}
}
return &ErrAuthorize{
Query: query,
Database: database,
Message: "create admin user first or disable authentication",
}
}
if u == nil {
return &ErrAuthorize{
Query: query,
Database: database,
Message: "no user provided",
}
}
return u.AuthorizeQuery(database, query)
}
func (u *UserInfo) AuthorizeQuery(database string, query *influxql.Query) error {
// Admin privilege allows the user to execute all statements.
if u.Admin {
return nil
}
// Check each statement in the query.
for _, stmt := range query.Statements {
// Get the privileges required to execute the statement.
privs, err := stmt.RequiredPrivileges()
if err != nil {
return err
}
// Make sure the user has the privileges required to execute
// each statement.
for _, p := range privs {
if p.Admin {
// Admin privilege already checked so statement requiring admin
// privilege cannot be run.
return &ErrAuthorize{
Query: query,
User: u.Name,
Database: database,
Message: fmt.Sprintf("statement '%s', requires admin privilege", stmt),
}
}
// Use the db name specified by the statement or the db
// name passed by the caller if one wasn't specified by
// the statement.
db := p.Name
if db == "" {
db = database
}
if !u.AuthorizeDatabase(p.Privilege, db) {
return &ErrAuthorize{
Query: query,
User: u.Name,
Database: database,
Message: fmt.Sprintf("statement '%s', requires %s on %s", stmt, p.Privilege.String(), db),
}
}
}
}
return nil
}
// ErrAuthorize represents an authorization error.
type ErrAuthorize struct {
Query *influxql.Query
User string
Database string
Message string
}
// Error returns the text of the error.
func (e ErrAuthorize) Error() string {
if e.User == "" {
return fmt.Sprint(e.Message)
}
return fmt.Sprintf("%s not authorized to execute %s", e.User, e.Message)
}

View File

@@ -0,0 +1,29 @@
package meta
import (
"fmt"
"github.com/influxdata/influxdb/influxql"
)
// WriteAuthorizer determines whether a user is authorized to write to a given database.
type WriteAuthorizer struct {
Client *Client
}
// NewWriteAuthorizer returns a new instance of WriteAuthorizer.
func NewWriteAuthorizer(c *Client) *WriteAuthorizer {
return &WriteAuthorizer{Client: c}
}
// AuthorizeWrite returns nil if the user has permission to write to the database.
func (a WriteAuthorizer) AuthorizeWrite(username, database string) error {
u, err := a.Client.User(username)
if err != nil || u == nil || !u.AuthorizeDatabase(influxql.WritePrivilege, database) {
return &ErrAuthorize{
Database: database,
Message: fmt.Sprintf("%s not authorized to write to %s", username, database),
}
}
return nil
}