Пример #1
0
// writeDescriptor takes a Table or Database descriptor and writes it
// if needed, incrementing the descriptor counter.
func (p *planner) writeDescriptor(key proto.Key, descriptor descriptorProto, ifNotExists bool) error {
	// Check whether key exists.
	gr, err := p.db.Get(key)
	if err != nil {
		return err
	}

	if gr.Exists() {
		if ifNotExists {
			// Noop.
			return nil
		}
		// Key exists, but we don't want it to: error out.
		// TODO(marc): prettify the error (strip stuff off the type name)
		return fmt.Errorf("%T \"%s\" already exists", descriptor, key.String())
	}

	// Increment unique descriptor counter.
	if ir, err := p.db.Inc(keys.DescIDGenerator, 1); err == nil {
		descriptor.SetID(uint32(ir.ValueInt() - 1))
	} else {
		return err
	}

	// TODO(pmattis): The error currently returned below is likely going to be
	// difficult to interpret.
	// TODO(pmattis): Need to handle if-not-exists here as well.
	descKey := keys.MakeDescMetadataKey(descriptor.GetID())
	return p.db.Txn(func(txn *client.Txn) error {
		b := &client.Batch{}
		b.CPut(key, descKey, nil)
		b.CPut(descKey, descriptor, nil)
		return txn.Commit(b)
	})
}
Пример #2
0
// Revoke removes privileges from users.
// Current status:
// - Target: DATABASE X only
// - Privileges: ALL, or one or more of READ, WRITE.
// TODO(marc): open questions:
// - should we have root always allowed and not present in the permissions list?
// - should we make users case-insensitive?
func (p *planner) Revoke(n *parser.Revoke) (planNode, error) {
	if len(n.Targets.Targets) == 0 {
		return nil, errEmptyDatabaseName
	}
	if len(n.Targets.Targets) != 1 {
		return nil, util.Errorf("TODO(marc): multiple targets not implemented")
	}

	// Lookup the database descriptor.
	// TODO(marc): iterate over n.Targets.Targets once the grammar supports more than one.
	dbDesc, err := p.getDatabaseDesc(n.Targets.Targets[0])
	if err != nil {
		return nil, err
	}

	if err := dbDesc.Revoke(n); err != nil {
		return nil, err
	}

	// Now update the descriptor.
	// TODO(marc): do this inside a transaction. This will be needed
	// when modifying multiple descriptors in the same op.
	descKey := keys.MakeDescMetadataKey(dbDesc.ID)
	if err := p.db.Put(descKey, dbDesc); err != nil {
		return nil, err
	}

	return &valuesNode{}, nil
}
Пример #3
0
func TestGrant(t *testing.T) {
	defer leaktest.AfterTest(t)
	s, sqlDB, kvDB := setup(t)
	defer cleanup(s, sqlDB)

	// The first `MaxReservedDescID` (plus 0) are set aside.
	expectedCounter := uint32(structured.MaxReservedDescID + 1)

	if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil {
		t.Fatal(err)
	}

	descKey := keys.MakeDescMetadataKey(expectedCounter)
	desc := structured.DatabaseDescriptor{}
	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 1 || desc.Read[0] != security.RootUser {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 1 || desc.Write[0] != security.RootUser {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Grant WRITE permissions.
	if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO foo`); err != nil {
		t.Fatal(err)
	}

	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 1 || desc.Read[0] != security.RootUser {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 2 || desc.Write[0] != "foo" || desc.Write[1] != security.RootUser {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Grant ALL Permissions.
	if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO bar`); err != nil {
		t.Fatal(err)
	}

	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 2 || desc.Read[0] != "bar" || desc.Read[1] != security.RootUser {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 3 || desc.Write[0] != "bar" || desc.Write[1] != "foo" || desc.Write[2] != security.RootUser {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Adding permissions to root is a noop.
	if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO root`); err != nil {
		t.Fatal(err)
	}
}
Пример #4
0
// CreateTable creates a table.
func (p *planner) CreateTable(n *parser.CreateTable) (planNode, error) {
	var err error
	n.Table, err = p.normalizeTableName(n.Table)
	if err != nil {
		return nil, err
	}

	dbID, err := p.lookupDatabase(n.Table.Database())
	if err != nil {
		return nil, err
	}

	desc, err := makeTableDesc(n)
	if err != nil {
		return nil, err
	}
	if err := desc.AllocateIDs(); err != nil {
		return nil, err
	}

	nameKey := keys.MakeNameMetadataKey(dbID, n.Table.Table())

	// This isn't strictly necessary as the conditional put below will fail if
	// the key already exists, but it seems good to avoid the table ID allocation
	// in most cases when the table already exists.
	if gr, err := p.db.Get(nameKey); err != nil {
		return nil, err
	} else if gr.Exists() {
		if n.IfNotExists {
			return &valuesNode{}, nil
		}
		return nil, fmt.Errorf("table \"%s\" already exists", n.Table)
	}

	ir, err := p.db.Inc(keys.DescIDGenerator, 1)
	if err != nil {
		return nil, err
	}
	desc.ID = uint32(ir.ValueInt() - 1)

	// TODO(pmattis): Be cognizant of error messages when this is ported to the
	// server. The error currently returned below is likely going to be difficult
	// to interpret.
	// TODO(pmattis): Need to handle if-not-exists here as well.
	err = p.db.Txn(func(txn *client.Txn) error {
		descKey := keys.MakeDescMetadataKey(desc.ID)
		b := &client.Batch{}
		b.CPut(nameKey, descKey, nil)
		b.Put(descKey, &desc)
		return txn.Commit(b)
	})
	if err != nil {
		return nil, err
	}
	return &valuesNode{}, nil
}
Пример #5
0
func (c *conn) CreateTable(p *parser.CreateTable, args []driver.Value) (*rows, error) {
	if err := c.normalizeTableName(p.Table); err != nil {
		return nil, err
	}

	dbID, err := c.lookupDatabase(p.Table.Qualifier)
	if err != nil {
		return nil, err
	}

	schema, err := makeSchema(p)
	if err != nil {
		return nil, err
	}
	desc := structured.TableDescFromSchema(schema)
	if err := structured.ValidateTableDesc(desc); err != nil {
		return nil, err
	}

	nameKey := keys.MakeNameMetadataKey(dbID, p.Table.Name)

	// This isn't strictly necessary as the conditional put below will fail if
	// the key already exists, but it seems good to avoid the table ID allocation
	// in most cases when the table already exists.
	if gr, err := c.db.Get(nameKey); err != nil {
		return nil, err
	} else if gr.Exists() {
		if p.IfNotExists {
			return &rows{}, nil
		}
		return nil, fmt.Errorf("table \"%s\" already exists", p.Table)
	}

	ir, err := c.db.Inc(keys.DescIDGenerator, 1)
	if err != nil {
		return nil, err
	}
	desc.ID = uint32(ir.ValueInt() - 1)

	// TODO(pmattis): Be cognizant of error messages when this is ported to the
	// server. The error currently returned below is likely going to be difficult
	// to interpret.
	err = c.db.Txn(func(txn *client.Txn) error {
		descKey := keys.MakeDescMetadataKey(desc.ID)
		b := &client.Batch{}
		b.CPut(nameKey, descKey, nil)
		b.Put(descKey, &desc)
		return txn.Commit(b)
	})
	if err != nil {
		// TODO(pmattis): Need to handle if-not-exists here as well.
		return nil, err
	}
	return &rows{}, nil
}
Пример #6
0
// CreateTable creates a table if it doesn't already exist.
func (s *Server) CreateTable(session *Session, p *parser.CreateTable, args []sqlwire.Datum, resp *sqlwire.Response) error {
	if err := s.normalizeTableName(session.Database, p.Table); err != nil {
		return err
	}

	dbID, err := s.lookupDatabase(p.Table.Qualifier)
	if err != nil {
		return err
	}

	desc, err := makeTableDesc(p)
	if err != nil {
		return err
	}
	if err := desc.AllocateIDs(); err != nil {
		return err
	}

	nameKey := keys.MakeNameMetadataKey(dbID, p.Table.Name)

	// This isn't strictly necessary as the conditional put below will fail if
	// the key already exists, but it seems good to avoid the table ID allocation
	// in most cases when the table already exists.
	if gr, err := s.db.Get(nameKey); err != nil {
		return err
	} else if gr.Exists() {
		if p.IfNotExists {
			return nil
		}
		return fmt.Errorf("table \"%s\" already exists", p.Table)
	}

	ir, err := s.db.Inc(keys.DescIDGenerator, 1)
	if err != nil {
		return err
	}
	desc.ID = uint32(ir.ValueInt() - 1)

	// TODO(pmattis): Be cognizant of error messages when this is ported to the
	// server. The error currently returned below is likely going to be difficult
	// to interpret.
	// TODO(pmattis): Need to handle if-not-exists here as well.
	return s.db.Txn(func(txn *client.Txn) error {
		descKey := keys.MakeDescMetadataKey(desc.ID)
		b := &client.Batch{}
		b.CPut(nameKey, descKey, nil)
		b.Put(descKey, &desc)
		return txn.Commit(b)
	})
}
Пример #7
0
// CreateTable creates a table from the specified schema. Table creation will
// fail if the table name is already in use. The table name is required to have
// the form "<namespace>.<table>".
func (db *DB) CreateTable(schema structured.TableSchema) error {
	schema.Name = strings.ToLower(schema.Name)
	desc := structured.TableDescFromSchema(schema)
	if err := structured.ValidateTableDesc(desc); err != nil {
		return err
	}

	nsID, name, err := db.lookupTable(desc.Name)
	if err != nil {
		return err
	}
	if name == "" {
		return fmt.Errorf("empty table name: %s", desc.Name)
	}
	nameKey := keys.MakeNameMetadataKey(nsID, name)

	// This isn't strictly necessary as the conditional put below will fail if
	// the key already exists, but it seems good to avoid the table ID allocation
	// in most cases when the table already exists.
	if gr, err := db.Get(nameKey); err != nil {
		return err
	} else if gr.Exists() {
		return fmt.Errorf("table \"%s\" already exists", desc.Name)
	}

	ir, err := db.Inc(keys.DescIDGenerator, 1)
	if err != nil {
		return err
	}
	desc.ID = uint32(ir.ValueInt() - 1)

	// TODO(pmattis): Be cognizant of error messages when this is ported to the
	// server. The error currently returned below is likely going to be difficult
	// to interpret.
	return db.Txn(func(txn *Txn) error {
		descKey := keys.MakeDescMetadataKey(desc.ID)
		b := &Batch{}
		b.CPut(nameKey, descKey, nil)
		b.Put(descKey, &desc)
		return txn.Commit(b)
	})
}
Пример #8
0
func TestDatabaseDescriptor(t *testing.T) {
	defer leaktest.AfterTest(t)
	s, sqlDB, kvDB := setup(t)
	defer cleanup(s, sqlDB)

	// The first `MaxReservedDescID` (plus 0) are set aside.
	expectedCounter := int64(structured.MaxReservedDescID + 1)

	// Test values before creating the database.
	// descriptor ID counter.
	if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil {
		t.Fatal(err)
	} else if ir.ValueInt() != expectedCounter {
		t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt())
	}

	// Database name.
	nameKey := keys.MakeNameMetadataKey(structured.RootNamespaceID, "test")
	if gr, err := kvDB.Get(nameKey); err != nil {
		t.Fatal(err)
	} else if gr.Exists() {
		t.Fatal("expected non-existing key")
	}

	if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil {
		t.Fatal(err)
	}
	expectedCounter++

	// Check keys again.
	// descriptor ID counter.
	if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil {
		t.Fatal(err)
	} else if ir.ValueInt() != expectedCounter {
		t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt())
	}

	// Database name.
	if gr, err := kvDB.Get(nameKey); err != nil {
		t.Fatal(err)
	} else if !gr.Exists() {
		t.Fatal("key is missing")
	}

	// database descriptor.
	descKey := keys.MakeDescMetadataKey(uint32(expectedCounter - 1))
	if gr, err := kvDB.Get(descKey); err != nil {
		t.Fatal(err)
	} else if !gr.Exists() {
		t.Fatal("key is missing")
	}

	// Now try to create it again. We should fail, but not increment the counter.
	if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil {
		t.Fatal("failure expected")
	}

	// Check keys again.
	// descriptor ID counter.
	if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil {
		t.Fatal(err)
	} else if ir.ValueInt() != expectedCounter {
		t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt())
	}

	// Database name.
	if gr, err := kvDB.Get(nameKey); err != nil {
		t.Fatal(err)
	} else if !gr.Exists() {
		t.Fatal("key is missing")
	}

	// database descriptor.
	if gr, err := kvDB.Get(descKey); err != nil {
		t.Fatal(err)
	} else if !gr.Exists() {
		t.Fatal("key is missing")
	}
}
Пример #9
0
func TestRevoke(t *testing.T) {
	defer leaktest.AfterTest(t)
	s, sqlDB, kvDB := setup(t)
	defer cleanup(s, sqlDB)

	// The first `MaxReservedDescID` (plus 0) are set aside.
	expectedCounter := uint32(structured.MaxReservedDescID + 1)

	if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil {
		t.Fatal(err)
	}

	descKey := keys.MakeDescMetadataKey(expectedCounter)
	desc := structured.DatabaseDescriptor{}
	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 1 || desc.Read[0] != security.RootUser {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 1 || desc.Write[0] != security.RootUser {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Add some permissions.
	if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO rw`); err != nil {
		t.Fatal(err)
	}
	if _, err := sqlDB.Exec(`GRANT READ ON DATABASE TEST TO reader`); err != nil {
		t.Fatal(err)
	}
	if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO writer`); err != nil {
		t.Fatal(err)
	}

	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 3 || len(desc.Write) != 3 {
		t.Fatalf("wrong read/write length: %d, %d", len(desc.Read), len(desc.Write))
	}

	// Test some revokes.
	if _, err := sqlDB.Exec(`REVOKE WRITE ON DATABASE TEST FROM writer,reader`); err != nil {
		t.Fatal(err)
	}

	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 3 {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 2 || desc.Write[0] != security.RootUser || desc.Write[1] != "rw" {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Remove ALL Permissions.
	if _, err := sqlDB.Exec(`REVOKE ALL ON DATABASE TEST FROM rw`); err != nil {
		t.Fatal(err)
	}

	if err := kvDB.GetProto(descKey, &desc); err != nil {
		t.Fatal(err)
	}
	if len(desc.Read) != 2 || desc.Read[0] != "reader" || desc.Read[1] != security.RootUser {
		t.Fatalf("wrong Read list: %+v", desc.Read)
	}
	if len(desc.Write) != 1 || desc.Write[0] != security.RootUser {
		t.Fatalf("wrong Write list: %+v", desc.Write)
	}

	// Removing permissions for "root" fails.
	if _, err := sqlDB.Exec(`REVOKE READ ON DATABASE TEST FROM root`); err == nil {
		t.Fatal("unexpected success")
	}
}