forked from TrueCloudLab/distribution
267 lines
7.7 KiB
Go
267 lines
7.7 KiB
Go
/*
|
|
Copyright 2015 Google Inc. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package bigtable
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"golang.org/x/net/context"
|
|
"google.golang.org/cloud"
|
|
btcspb "google.golang.org/cloud/bigtable/internal/cluster_service_proto"
|
|
bttspb "google.golang.org/cloud/bigtable/internal/table_service_proto"
|
|
"google.golang.org/cloud/internal/transport"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
const adminAddr = "bigtabletableadmin.googleapis.com:443"
|
|
|
|
// AdminClient is a client type for performing admin operations within a specific cluster.
|
|
type AdminClient struct {
|
|
conn *grpc.ClientConn
|
|
tClient bttspb.BigtableTableServiceClient
|
|
|
|
project, zone, cluster string
|
|
}
|
|
|
|
// NewAdminClient creates a new AdminClient for a given project, zone and cluster.
|
|
func NewAdminClient(ctx context.Context, project, zone, cluster string, opts ...cloud.ClientOption) (*AdminClient, error) {
|
|
o := []cloud.ClientOption{
|
|
cloud.WithEndpoint(adminAddr),
|
|
cloud.WithScopes(AdminScope),
|
|
cloud.WithUserAgent(clientUserAgent),
|
|
}
|
|
o = append(o, opts...)
|
|
conn, err := transport.DialGRPC(ctx, o...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dialing: %v", err)
|
|
}
|
|
return &AdminClient{
|
|
conn: conn,
|
|
tClient: bttspb.NewBigtableTableServiceClient(conn),
|
|
|
|
project: project,
|
|
zone: zone,
|
|
cluster: cluster,
|
|
}, nil
|
|
}
|
|
|
|
// Close closes the AdminClient.
|
|
func (ac *AdminClient) Close() {
|
|
ac.conn.Close()
|
|
}
|
|
|
|
func (ac *AdminClient) clusterPrefix() string {
|
|
return fmt.Sprintf("projects/%s/zones/%s/clusters/%s", ac.project, ac.zone, ac.cluster)
|
|
}
|
|
|
|
// Tables returns a list of the tables in the cluster.
|
|
func (ac *AdminClient) Tables(ctx context.Context) ([]string, error) {
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.ListTablesRequest{
|
|
Name: prefix,
|
|
}
|
|
res, err := ac.tClient.ListTables(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
names := make([]string, 0, len(res.Tables))
|
|
for _, tbl := range res.Tables {
|
|
names = append(names, strings.TrimPrefix(tbl.Name, prefix+"/tables/"))
|
|
}
|
|
return names, nil
|
|
}
|
|
|
|
// CreateTable creates a new table in the cluster.
|
|
// This method may return before the table's creation is complete.
|
|
func (ac *AdminClient) CreateTable(ctx context.Context, table string) error {
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.CreateTableRequest{
|
|
Name: prefix,
|
|
TableId: table,
|
|
}
|
|
_, err := ac.tClient.CreateTable(ctx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CreateColumnFamily creates a new column family in a table.
|
|
func (ac *AdminClient) CreateColumnFamily(ctx context.Context, table, family string) error {
|
|
// TODO(dsymonds): Permit specifying gcexpr and any other family settings.
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.CreateColumnFamilyRequest{
|
|
Name: prefix + "/tables/" + table,
|
|
ColumnFamilyId: family,
|
|
}
|
|
_, err := ac.tClient.CreateColumnFamily(ctx, req)
|
|
return err
|
|
}
|
|
|
|
// DeleteTable deletes a table and all of its data.
|
|
func (ac *AdminClient) DeleteTable(ctx context.Context, table string) error {
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.DeleteTableRequest{
|
|
Name: prefix + "/tables/" + table,
|
|
}
|
|
_, err := ac.tClient.DeleteTable(ctx, req)
|
|
return err
|
|
}
|
|
|
|
// DeleteColumnFamily deletes a column family in a table and all of its data.
|
|
func (ac *AdminClient) DeleteColumnFamily(ctx context.Context, table, family string) error {
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.DeleteColumnFamilyRequest{
|
|
Name: prefix + "/tables/" + table + "/columnFamilies/" + family,
|
|
}
|
|
_, err := ac.tClient.DeleteColumnFamily(ctx, req)
|
|
return err
|
|
}
|
|
|
|
// TableInfo represents information about a table.
|
|
type TableInfo struct {
|
|
Families []string
|
|
}
|
|
|
|
// TableInfo retrieves information about a table.
|
|
func (ac *AdminClient) TableInfo(ctx context.Context, table string) (*TableInfo, error) {
|
|
prefix := ac.clusterPrefix()
|
|
req := &bttspb.GetTableRequest{
|
|
Name: prefix + "/tables/" + table,
|
|
}
|
|
res, err := ac.tClient.GetTable(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ti := &TableInfo{}
|
|
for fam := range res.ColumnFamilies {
|
|
ti.Families = append(ti.Families, fam)
|
|
}
|
|
return ti, nil
|
|
}
|
|
|
|
// SetGCPolicy specifies which cells in a column family should be garbage collected.
|
|
// GC executes opportunistically in the background; table reads may return data
|
|
// matching the GC policy.
|
|
func (ac *AdminClient) SetGCPolicy(ctx context.Context, table, family string, policy GCPolicy) error {
|
|
prefix := ac.clusterPrefix()
|
|
tbl, err := ac.tClient.GetTable(ctx, &bttspb.GetTableRequest{
|
|
Name: prefix + "/tables/" + table,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fam, ok := tbl.ColumnFamilies[family]
|
|
if !ok {
|
|
return fmt.Errorf("unknown column family %q", family)
|
|
}
|
|
fam.GcRule = policy.proto()
|
|
_, err = ac.tClient.UpdateColumnFamily(ctx, fam)
|
|
return err
|
|
}
|
|
|
|
const clusterAdminAddr = "bigtableclusteradmin.googleapis.com:443"
|
|
|
|
// ClusterAdminClient is a client type for performing admin operations on clusters.
|
|
// These operations can be substantially more dangerous than those provided by AdminClient.
|
|
type ClusterAdminClient struct {
|
|
conn *grpc.ClientConn
|
|
cClient btcspb.BigtableClusterServiceClient
|
|
|
|
project string
|
|
}
|
|
|
|
// NewClusterAdminClient creates a new ClusterAdminClient for a given project.
|
|
func NewClusterAdminClient(ctx context.Context, project string, opts ...cloud.ClientOption) (*ClusterAdminClient, error) {
|
|
o := []cloud.ClientOption{
|
|
cloud.WithEndpoint(clusterAdminAddr),
|
|
cloud.WithScopes(ClusterAdminScope),
|
|
cloud.WithUserAgent(clientUserAgent),
|
|
}
|
|
o = append(o, opts...)
|
|
conn, err := transport.DialGRPC(ctx, o...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dialing: %v", err)
|
|
}
|
|
return &ClusterAdminClient{
|
|
conn: conn,
|
|
cClient: btcspb.NewBigtableClusterServiceClient(conn),
|
|
|
|
project: project,
|
|
}, nil
|
|
}
|
|
|
|
// Close closes the ClusterAdminClient.
|
|
func (cac *ClusterAdminClient) Close() {
|
|
cac.conn.Close()
|
|
}
|
|
|
|
// ClusterInfo represents information about a cluster.
|
|
type ClusterInfo struct {
|
|
Name string // name of the cluster
|
|
Zone string // GCP zone of the cluster (e.g. "us-central1-a")
|
|
DisplayName string // display name for UIs
|
|
ServeNodes int // number of allocated serve nodes
|
|
}
|
|
|
|
var clusterNameRegexp = regexp.MustCompile(`^projects/([^/]+)/zones/([^/]+)/clusters/([a-z][-a-z0-9]*)$`)
|
|
|
|
// Clusters returns a list of clusters in the project.
|
|
func (cac *ClusterAdminClient) Clusters(ctx context.Context) ([]*ClusterInfo, error) {
|
|
req := &btcspb.ListClustersRequest{
|
|
Name: "projects/" + cac.project,
|
|
}
|
|
res, err := cac.cClient.ListClusters(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// TODO(dsymonds): Deal with failed_zones.
|
|
var cis []*ClusterInfo
|
|
for _, c := range res.Clusters {
|
|
m := clusterNameRegexp.FindStringSubmatch(c.Name)
|
|
if m == nil {
|
|
return nil, fmt.Errorf("malformed cluster name %q", c.Name)
|
|
}
|
|
cis = append(cis, &ClusterInfo{
|
|
Name: m[3],
|
|
Zone: m[2],
|
|
DisplayName: c.DisplayName,
|
|
ServeNodes: int(c.ServeNodes),
|
|
})
|
|
}
|
|
return cis, nil
|
|
}
|
|
|
|
/* TODO(dsymonds): Re-enable when there's a ClusterAdmin API.
|
|
|
|
// SetClusterSize sets the number of server nodes for this cluster.
|
|
func (ac *AdminClient) SetClusterSize(ctx context.Context, nodes int) error {
|
|
req := &btcspb.GetClusterRequest{
|
|
Name: ac.clusterPrefix(),
|
|
}
|
|
clu, err := ac.cClient.GetCluster(ctx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
clu.ServeNodes = int32(nodes)
|
|
_, err = ac.cClient.UpdateCluster(ctx, clu)
|
|
return err
|
|
}
|
|
|
|
*/
|