201 lines
5.6 KiB
Go
201 lines
5.6 KiB
Go
package backup_restore
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/influxdata/influx-cli/v2/api"
|
|
)
|
|
|
|
type FileCompression int
|
|
|
|
const (
|
|
NoCompression FileCompression = iota
|
|
GzipCompression
|
|
)
|
|
|
|
func (c *FileCompression) Set(v string) error {
|
|
switch v {
|
|
case "none":
|
|
*c = NoCompression
|
|
case "gzip":
|
|
*c = GzipCompression
|
|
default:
|
|
return fmt.Errorf("unsupported format: %q", v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c FileCompression) String() string {
|
|
switch c {
|
|
case NoCompression:
|
|
return "none"
|
|
case GzipCompression:
|
|
return "gzip"
|
|
default:
|
|
panic("Impossible!")
|
|
}
|
|
}
|
|
|
|
const (
|
|
ManifestExtension = "manifest"
|
|
ManifestVersion = 2
|
|
)
|
|
|
|
type Manifest struct {
|
|
Version int `json:"manifestVersion"`
|
|
KV ManifestFileEntry `json:"kv"`
|
|
SQL *ManifestFileEntry `json:"sql,omitempty"`
|
|
Buckets []ManifestBucketEntry `json:"buckets"`
|
|
}
|
|
|
|
type ManifestFileEntry struct {
|
|
FileName string `json:"fileName"`
|
|
Size int64 `json:"size"`
|
|
Compression FileCompression `json:"compression"`
|
|
}
|
|
|
|
type ManifestBucketEntry struct {
|
|
OrganizationID string `json:"organizationID"`
|
|
OrganizationName string `json:"organizationName"`
|
|
BucketID string `json:"bucketID"`
|
|
BucketName string `json:"bucketName"`
|
|
Description *string `json:"description,omitempty"`
|
|
DefaultRetentionPolicy string `json:"defaultRetentionPolicy"`
|
|
RetentionPolicies []ManifestRetentionPolicy `json:"retentionPolicies"`
|
|
}
|
|
|
|
type ManifestRetentionPolicy struct {
|
|
Name string `json:"name"`
|
|
ReplicaN int32 `json:"replicaN"`
|
|
Duration int64 `json:"duration"`
|
|
ShardGroupDuration int64 `json:"shardGroupDuration"`
|
|
ShardGroups []ManifestShardGroup `json:"shardGroups"`
|
|
Subscriptions []ManifestSubscription `json:"subscriptions"`
|
|
}
|
|
|
|
type ManifestShardGroup struct {
|
|
ID int64 `json:"id"`
|
|
StartTime time.Time `json:"startTime"`
|
|
EndTime time.Time `json:"endTime"`
|
|
DeletedAt *time.Time `json:"deletedAt,omitempty"`
|
|
TruncatedAt *time.Time `json:"truncatedAt,omitempty"`
|
|
Shards []ManifestShardEntry `json:"shards"`
|
|
}
|
|
|
|
type ManifestShardEntry struct {
|
|
ID int64 `json:"id"`
|
|
ShardOwners []ShardOwnerEntry `json:"shardOwners"`
|
|
ManifestFileEntry
|
|
}
|
|
|
|
type ShardOwnerEntry struct {
|
|
NodeID int64 `json:"nodeID"`
|
|
}
|
|
|
|
type ManifestSubscription struct {
|
|
Name string `json:"name"`
|
|
Mode string `json:"mode"`
|
|
Destinations []string `json:"destinations"`
|
|
}
|
|
|
|
func ConvertBucketManifest(manifest api.BucketMetadataManifest, getShard func(shardId int64) (*ManifestFileEntry, error)) (ManifestBucketEntry, error) {
|
|
m := ManifestBucketEntry{
|
|
OrganizationID: manifest.OrganizationID,
|
|
OrganizationName: manifest.OrganizationName,
|
|
BucketID: manifest.BucketID,
|
|
BucketName: manifest.BucketName,
|
|
Description: manifest.Description,
|
|
DefaultRetentionPolicy: manifest.DefaultRetentionPolicy,
|
|
RetentionPolicies: make([]ManifestRetentionPolicy, len(manifest.RetentionPolicies)),
|
|
}
|
|
|
|
for i, rp := range manifest.RetentionPolicies {
|
|
var err error
|
|
m.RetentionPolicies[i], err = ConvertRetentionPolicy(rp, getShard)
|
|
if err != nil {
|
|
return ManifestBucketEntry{}, err
|
|
}
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func ConvertRetentionPolicy(manifest api.RetentionPolicyManifest, getShard func(shardId int64) (*ManifestFileEntry, error)) (ManifestRetentionPolicy, error) {
|
|
m := ManifestRetentionPolicy{
|
|
Name: manifest.Name,
|
|
ReplicaN: manifest.ReplicaN,
|
|
Duration: manifest.Duration,
|
|
ShardGroupDuration: manifest.ShardGroupDuration,
|
|
ShardGroups: make([]ManifestShardGroup, len(manifest.ShardGroups)),
|
|
Subscriptions: make([]ManifestSubscription, len(manifest.Subscriptions)),
|
|
}
|
|
|
|
for i, sg := range manifest.ShardGroups {
|
|
var err error
|
|
m.ShardGroups[i], err = ConvertShardGroup(sg, getShard)
|
|
if err != nil {
|
|
return ManifestRetentionPolicy{}, err
|
|
}
|
|
}
|
|
|
|
for i, s := range manifest.Subscriptions {
|
|
m.Subscriptions[i] = ManifestSubscription{
|
|
Name: s.Name,
|
|
Mode: s.Mode,
|
|
Destinations: s.Destinations,
|
|
}
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func ConvertShardGroup(manifest api.ShardGroupManifest, getShard func(shardId int64) (*ManifestFileEntry, error)) (ManifestShardGroup, error) {
|
|
m := ManifestShardGroup{
|
|
ID: manifest.Id,
|
|
StartTime: manifest.StartTime,
|
|
EndTime: manifest.EndTime,
|
|
DeletedAt: manifest.DeletedAt,
|
|
TruncatedAt: manifest.TruncatedAt,
|
|
Shards: make([]ManifestShardEntry, 0, len(manifest.Shards)),
|
|
}
|
|
|
|
for _, sh := range manifest.Shards {
|
|
maybeShard, err := ConvertShard(sh, getShard)
|
|
if err != nil {
|
|
return ManifestShardGroup{}, err
|
|
}
|
|
// Shard deleted mid-backup.
|
|
if maybeShard == nil {
|
|
continue
|
|
}
|
|
m.Shards = append(m.Shards, *maybeShard)
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func ConvertShard(manifest api.ShardManifest, getShard func(shardId int64) (*ManifestFileEntry, error)) (*ManifestShardEntry, error) {
|
|
shardFileInfo, err := getShard(manifest.Id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to download snapshot of shard %d: %w", manifest.Id, err)
|
|
}
|
|
if shardFileInfo == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
m := ManifestShardEntry{
|
|
ID: manifest.Id,
|
|
ShardOwners: make([]ShardOwnerEntry, len(manifest.ShardOwners)),
|
|
ManifestFileEntry: *shardFileInfo,
|
|
}
|
|
|
|
for i, o := range manifest.ShardOwners {
|
|
m.ShardOwners[i] = ShardOwnerEntry{
|
|
NodeID: o.NodeID,
|
|
}
|
|
}
|
|
|
|
return &m, nil
|
|
}
|