feat: add logic for reading manifest from bolt file (#183)

This commit is contained in:
Daniel Moran 2021-07-09 09:27:53 -04:00 committed by GitHub
parent 4452aac87d
commit 9b54bcb17f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 3746 additions and 0 deletions

349
clients/backup/bolt.go Normal file
View File

@ -0,0 +1,349 @@
package backup
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/gogo/protobuf/proto"
"github.com/influxdata/influx-cli/v2/api"
"github.com/influxdata/influx-cli/v2/clients/backup/internal"
"go.etcd.io/bbolt"
)
//go:generate protoc --gogo_out=. internal/meta.proto
// NOTE: An unfortunate naming collision below. Bolt calls its databases "buckets".
// These are the names that were used in the metadata DB for 2.0.x versions of influxdb.
var (
bucketsBoltBucket = []byte("bucketsv1")
organizationsBoltBucket = []byte("organizationsv1")
v1MetadataBoltBucket = []byte("v1_tsm1_metadata")
v1MetadataBoltKey = []byte("meta.db")
)
// influxdbBucketSchema models the JSON structure used by InfluxDB 2.0.x to serialize
// bucket metadata in the embedded KV store.
type influxdbBucketSchema struct {
ID string `json:"id"`
OrgID string `json:"orgID"`
Type int `json:"type"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
RetentionPeriod time.Duration `json:"retentionPeriod"`
ShardGroupDuration time.Duration `json:"ShardGroupDuration"`
}
// influxdbOrganizationSchema models the JSON structure used by InfluxDB 2.0.x to serialize
// organization metadata in the embedded KV store.
type influxdbOrganizationSchema struct {
ID string `json:"id"`
Name string `json:"name"`
}
// influxdbV1DatabaseInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// database info in the embedded KV store.
type influxdbV1DatabaseInfo struct {
Name string
DefaultRetentionPolicy string
RetentionPolicies []influxdbV1RetentionPolicyInfo
}
// influxdbV1RetentionPolicyInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// retention-policy info in the embedded KV store.
type influxdbV1RetentionPolicyInfo struct {
Name string
ReplicaN int32
Duration int64
ShardGroupDuration int64
ShardGroups []influxdbV1ShardGroupInfo
Subscriptions []influxdbV1SubscriptionInfo
}
// influxdbV1ShardGroupInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// shard-group info in the embedded KV store.
type influxdbV1ShardGroupInfo struct {
ID int64
StartTime time.Time
EndTime time.Time
DeletedAt time.Time
Shards []influxdbV1ShardInfo
TruncatedAt time.Time
}
// influxdbV1ShardInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// shard info in the embedded KV store.
type influxdbV1ShardInfo struct {
ID int64
Owners []influxdbV1ShardOwnerInfo
}
// inflxudbV1ShardOwnerInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// shard-owner info in the embedded KV store.
type influxdbV1ShardOwnerInfo struct {
NodeID int64
}
// influxdbV1SubscriptionInfo models the protobuf structure used by InfluxDB 2.0.x to serialize
// subscription info in the embedded KV store.
type influxdbV1SubscriptionInfo struct {
Name string
Mode string
Destinations []string
}
// extractBucketManifest reads a boltdb backed up from InfluxDB 2.0.x, converting a subset of the
// metadata it contains into a set of 2.1.x bucket manifests.
func extractBucketManifest(boltPath string) ([]api.BucketMetadataManifest, error) {
db, err := bbolt.Open(boltPath, 0666, &bbolt.Options{ReadOnly: true, Timeout: 1 * time.Second})
if err != nil {
// Hack to give a slightly nicer error message for a known failure mode when bolt calls
// mmap on a file system that doesn't support the MAP_SHARED option.
//
// See: https://github.com/boltdb/bolt/issues/272
// See: https://stackoverflow.com/a/18421071
if err.Error() == "invalid argument" {
return nil, fmt.Errorf("unable to open boltdb: mmap of %q may not support the MAP_SHARED option", boltPath)
}
return nil, fmt.Errorf("unable to open boltdb: %w", err)
}
defer db.Close()
// Read raw metadata needed to construct a manifest.
var buckets []influxdbBucketSchema
orgNamesById := map[string]string{}
dbInfoByBucketId := map[string]influxdbV1DatabaseInfo{}
if err := db.View(func(tx *bbolt.Tx) error {
bucketDB := tx.Bucket(bucketsBoltBucket)
if bucketDB == nil {
return errors.New("bucket metadata not found in local KV store")
}
if err := bucketDB.ForEach(func(k, v []byte) error {
var b influxdbBucketSchema
if err := json.Unmarshal(v, &b); err != nil {
return err
}
if b.Type != 1 { // 1 == "system"
buckets = append(buckets, b)
}
return nil
}); err != nil {
return fmt.Errorf("failed to read bucket metadata from local KV store: %w", err)
}
orgsDB := tx.Bucket(organizationsBoltBucket)
if orgsDB == nil {
return errors.New("organization metadata not found in local KV store")
}
if err := orgsDB.ForEach(func(k, v []byte) error {
var o influxdbOrganizationSchema
if err := json.Unmarshal(v, &o); err != nil {
return err
}
orgNamesById[o.ID] = o.Name
return nil
}); err != nil {
return fmt.Errorf("failed to read organization metadata from local KV store: %w", err)
}
v1DB := tx.Bucket(v1MetadataBoltBucket)
if v1DB == nil {
return errors.New("v1 database info not found in local KV store")
}
fullMeta := v1DB.Get(v1MetadataBoltKey)
if fullMeta == nil {
return errors.New("v1 database info not found in local KV store")
}
var pb internal.Data
if err := proto.Unmarshal(fullMeta, &pb); err != nil {
return fmt.Errorf("failed to unmarshal v1 database info: %w", err)
}
for _, rawDBI := range pb.GetDatabases() {
if rawDBI == nil {
continue
}
unmarshalled := unmarshalRawDBI(*rawDBI)
dbInfoByBucketId[unmarshalled.Name] = unmarshalled
}
return nil
}); err != nil {
return nil, err
}
manifests := make([]api.BucketMetadataManifest, len(buckets))
for i, b := range buckets {
orgName, ok := orgNamesById[b.OrgID]
if !ok {
return nil, fmt.Errorf("local KV store in inconsistent state: no organization found with ID %q", b.OrgID)
}
dbi, ok := dbInfoByBucketId[b.ID]
if !ok {
return nil, fmt.Errorf("local KV store in inconsistent state: no V1 database info found for bucket %q", b.Name)
}
manifests[i] = combineMetadata(b, orgName, dbi)
}
return manifests, nil
}
func unmarshalRawDBI(rawDBI internal.DatabaseInfo) influxdbV1DatabaseInfo {
dbi := influxdbV1DatabaseInfo{
Name: rawDBI.GetName(),
DefaultRetentionPolicy: rawDBI.GetDefaultRetentionPolicy(),
RetentionPolicies: make([]influxdbV1RetentionPolicyInfo, 0, len(rawDBI.GetRetentionPolicies())),
}
for _, rp := range rawDBI.GetRetentionPolicies() {
if rp == nil {
continue
}
dbi.RetentionPolicies = append(dbi.RetentionPolicies, unmarshalRawRPI(*rp))
}
return dbi
}
func unmarshalRawRPI(rawRPI internal.RetentionPolicyInfo) influxdbV1RetentionPolicyInfo {
rpi := influxdbV1RetentionPolicyInfo{
Name: rawRPI.GetName(),
ReplicaN: int32(rawRPI.GetReplicaN()),
Duration: rawRPI.GetDuration(),
ShardGroupDuration: rawRPI.GetShardGroupDuration(),
ShardGroups: make([]influxdbV1ShardGroupInfo, 0, len(rawRPI.GetShardGroups())),
Subscriptions: make([]influxdbV1SubscriptionInfo, 0, len(rawRPI.GetSubscriptions())),
}
for _, sg := range rawRPI.GetShardGroups() {
if sg == nil {
continue
}
rpi.ShardGroups = append(rpi.ShardGroups, unmarshalRawSGI(*sg))
}
for _, s := range rawRPI.GetSubscriptions() {
if s == nil {
continue
}
rpi.Subscriptions = append(rpi.Subscriptions, influxdbV1SubscriptionInfo{
Name: s.GetName(),
Mode: s.GetMode(),
Destinations: s.GetDestinations(),
})
}
return rpi
}
func unmarshalRawSGI(rawSGI internal.ShardGroupInfo) influxdbV1ShardGroupInfo {
sgi := influxdbV1ShardGroupInfo{
ID: int64(rawSGI.GetID()),
StartTime: time.Unix(0, rawSGI.GetStartTime()).UTC(),
EndTime: time.Unix(0, rawSGI.GetEndTime()).UTC(),
DeletedAt: time.Unix(0, rawSGI.GetDeletedAt()).UTC(),
Shards: make([]influxdbV1ShardInfo, 0, len(rawSGI.GetShards())),
TruncatedAt: time.Unix(0, rawSGI.GetTruncatedAt()).UTC(),
}
for _, s := range rawSGI.GetShards() {
if s == nil {
continue
}
sgi.Shards = append(sgi.Shards, unmarshalRawShard(*s))
}
return sgi
}
func unmarshalRawShard(rawShard internal.ShardInfo) influxdbV1ShardInfo {
si := influxdbV1ShardInfo{
ID: int64(rawShard.GetID()),
}
// If deprecated "OwnerIDs" exists then convert it to "Owners" format.
//lint:ignore SA1019 we need to check for the presence of the deprecated field so we can convert it
oldStyleOwnerIds := rawShard.GetOwnerIDs()
if len(oldStyleOwnerIds) > 0 {
si.Owners = make([]influxdbV1ShardOwnerInfo, len(oldStyleOwnerIds))
for i, oid := range oldStyleOwnerIds {
si.Owners[i] = influxdbV1ShardOwnerInfo{NodeID: int64(oid)}
}
} else {
si.Owners = make([]influxdbV1ShardOwnerInfo, 0, len(rawShard.GetOwners()))
for _, o := range rawShard.GetOwners() {
if o == nil {
continue
}
si.Owners = append(si.Owners, influxdbV1ShardOwnerInfo{NodeID: int64(o.GetNodeID())})
}
}
return si
}
func combineMetadata(bucket influxdbBucketSchema, orgName string, dbi influxdbV1DatabaseInfo) api.BucketMetadataManifest {
m := api.BucketMetadataManifest{
OrganizationID: bucket.OrgID,
OrganizationName: orgName,
BucketID: bucket.ID,
BucketName: bucket.Name,
DefaultRetentionPolicy: dbi.DefaultRetentionPolicy,
RetentionPolicies: make([]api.RetentionPolicyManifest, len(dbi.RetentionPolicies)),
}
if bucket.Description != nil && *bucket.Description != "" {
m.Description = bucket.Description
}
for i, rp := range dbi.RetentionPolicies {
m.RetentionPolicies[i] = convertRPI(rp)
}
return m
}
func convertRPI(rpi influxdbV1RetentionPolicyInfo) api.RetentionPolicyManifest {
m := api.RetentionPolicyManifest{
Name: rpi.Name,
ReplicaN: rpi.ReplicaN,
Duration: rpi.Duration,
ShardGroupDuration: rpi.ShardGroupDuration,
ShardGroups: make([]api.ShardGroupManifest, len(rpi.ShardGroups)),
Subscriptions: make([]api.SubscriptionManifest, len(rpi.Subscriptions)),
}
for i, sg := range rpi.ShardGroups {
m.ShardGroups[i] = convertSGI(sg)
}
for i, s := range rpi.Subscriptions {
m.Subscriptions[i] = api.SubscriptionManifest{
Name: s.Name,
Mode: s.Mode,
Destinations: s.Destinations,
}
}
return m
}
func convertSGI(sgi influxdbV1ShardGroupInfo) api.ShardGroupManifest {
m := api.ShardGroupManifest{
Id: sgi.ID,
StartTime: sgi.StartTime,
EndTime: sgi.EndTime,
Shards: make([]api.ShardManifest, len(sgi.Shards)),
}
if sgi.DeletedAt.Unix() != 0 {
m.DeletedAt = &sgi.DeletedAt
}
if sgi.TruncatedAt.Unix() != 0 {
m.TruncatedAt = &sgi.TruncatedAt
}
for i, s := range sgi.Shards {
m.Shards[i] = convertShard(s)
}
return m
}
func convertShard(shard influxdbV1ShardInfo) api.ShardManifest {
m := api.ShardManifest{
Id: shard.ID,
ShardOwners: make([]api.ShardOwner, len(shard.Owners)),
}
for i, o := range shard.Owners {
m.ShardOwners[i] = api.ShardOwner{NodeID: o.NodeID}
}
return m
}

View File

@ -0,0 +1,106 @@
package backup
import (
"compress/gzip"
"io"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/influxdata/influx-cli/v2/api"
"github.com/stretchr/testify/require"
)
const testFile = "testdata/test.bolt.gz"
func TestExtractManifest(t *testing.T) {
t.Parallel()
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows: https://github.com/etcd-io/bbolt/issues/252")
}
// Extract our example input into a format the bbolt client can use.
boltIn, err := os.Open(testFile)
require.NoError(t, err)
defer boltIn.Close()
gzipIn, err := gzip.NewReader(boltIn)
require.NoError(t, err)
defer gzipIn.Close()
tmp, err := os.MkdirTemp("", "")
require.NoError(t, err)
defer os.RemoveAll(tmp)
tmpBoltPath := filepath.Join(tmp, "test.bolt")
tmpBolt, err := os.Create(tmpBoltPath)
require.NoError(t, err)
_, err = io.Copy(tmpBolt, gzipIn)
require.NoError(t, tmpBolt.Close())
require.NoError(t, err)
extracted, err := extractBucketManifest(tmpBoltPath)
require.NoError(t, err)
expected := []api.BucketMetadataManifest{
{
OrganizationID: "80c29010030b3d83",
OrganizationName: "test2",
BucketID: "5379ef2d1655b0ab",
BucketName: "test3",
DefaultRetentionPolicy: "autogen",
RetentionPolicies: []api.RetentionPolicyManifest{
{
Name: "autogen",
ReplicaN: 1,
Duration: 0,
ShardGroupDuration: 604800000000000,
ShardGroups: []api.ShardGroupManifest{},
Subscriptions: []api.SubscriptionManifest{},
},
},
},
{
OrganizationID: "375477729f9d7262",
OrganizationName: "test",
BucketID: "cce01ef3783e3678",
BucketName: "test2",
DefaultRetentionPolicy: "autogen",
RetentionPolicies: []api.RetentionPolicyManifest{
{
Name: "autogen",
ReplicaN: 1,
Duration: 0,
ShardGroupDuration: 3600000000000,
ShardGroups: []api.ShardGroupManifest{},
Subscriptions: []api.SubscriptionManifest{},
},
},
},
{
OrganizationID: "375477729f9d7262",
OrganizationName: "test",
BucketID: "d66c5360b5aa91b4",
BucketName: "test",
DefaultRetentionPolicy: "autogen",
RetentionPolicies: []api.RetentionPolicyManifest{
{
Name: "autogen",
ReplicaN: 1,
Duration: 259200000000000,
ShardGroupDuration: 86400000000000,
ShardGroups: []api.ShardGroupManifest{},
Subscriptions: []api.SubscriptionManifest{},
},
},
},
}
require.Equal(t, len(expected), len(extracted))
require.Equal(t, expected, extracted)
for _, e := range expected {
require.Contains(t, extracted, e)
}
}

View File

@ -0,0 +1,12 @@
# V1 Meta Protobufs
For compatibility with backups made via the v2.0.x `influx` CLI, we include logic
for opening & reading backed-up KV stores to derive bucket manifests. Part of that
process requires reading & unmarshalling V1 database info, serialized as protobuf.
To support that requirement, we've copied the `meta.proto` definition out of `influxdb`
and into this repository. This file isn't intended to be modified.
If `meta.pb.go` ever needs to be re-generated, follow these steps:
1. Install `protoc` (i.e. via `brew install protobuf`)
2. Run `go install github.com/gogo/protobuf/protoc-gen-gogo` from within this repository
3. Run `go generate <path to clients/backup>`

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,397 @@
// NOTE: This is a snapshot of the schema used to serialize V1 database info
// in the 2.0.x line of InfluxDB. The copy is here so we can support backing
// up from older DB versions, it's not intended to be kept up-to-date.
package internal;
//========================================================================
//
// 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;
}

BIN
clients/backup/testdata/test.bolt.gz vendored Normal file

Binary file not shown.

2
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/fatih/color v1.9.0
github.com/fujiwara/shapeio v1.0.0
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.5.0
github.com/google/go-cmp v0.5.5
github.com/google/go-jsonnet v0.17.0
@ -17,6 +18,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/stretchr/testify v1.7.0
github.com/urfave/cli v1.22.5
go.etcd.io/bbolt v1.3.6
golang.org/x/text v0.3.3
golang.org/x/tools v0.1.0
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c

12
go.sum
View File

@ -21,6 +21,8 @@ github.com/fujiwara/shapeio v1.0.0 h1:xG5D9oNqCSUUbryZ/jQV3cqe1v2suEjwPIcEg1gKM8
github.com/fujiwara/shapeio v1.0.0/go.mod h1:LmEmu6L/8jetyj1oewewFb7bZCNRwE7wLCUNzDLaLVA=
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d h1:r3mStZSyjKhEcgbJ5xtv7kT5PZw/tDiFBTMgQx2qsXE=
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
@ -31,6 +33,7 @@ github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDG
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -68,18 +71,24 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -87,6 +96,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -97,7 +107,9 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiT
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -11,6 +11,7 @@ package influxcli
import (
_ "github.com/daixiang0/gci"
_ "github.com/gogo/protobuf/protoc-gen-gogo"
_ "github.com/golang/mock/mockgen"
_ "golang.org/x/tools/cmd/goimports"
_ "honnef.co/go/tools/cmd/staticcheck"