2021-01-21 21:09:15 +00:00
|
|
|
package etcdsnapshot
|
|
|
|
|
|
|
|
import (
|
2022-02-25 21:00:00 +00:00
|
|
|
"encoding/json"
|
2021-01-21 21:09:15 +00:00
|
|
|
"errors"
|
2021-05-11 23:59:33 +00:00
|
|
|
"fmt"
|
2021-01-21 21:09:15 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2022-02-25 21:00:00 +00:00
|
|
|
"strings"
|
2021-05-11 23:59:33 +00:00
|
|
|
"text/tabwriter"
|
|
|
|
"time"
|
2021-01-21 21:09:15 +00:00
|
|
|
|
|
|
|
"github.com/erikdubbelboer/gspt"
|
|
|
|
"github.com/rancher/k3s/pkg/cli/cmds"
|
|
|
|
"github.com/rancher/k3s/pkg/cluster"
|
|
|
|
"github.com/rancher/k3s/pkg/daemons/config"
|
|
|
|
"github.com/rancher/k3s/pkg/etcd"
|
|
|
|
"github.com/rancher/k3s/pkg/server"
|
2021-06-01 19:29:46 +00:00
|
|
|
util2 "github.com/rancher/k3s/pkg/util"
|
2021-01-21 21:09:15 +00:00
|
|
|
"github.com/rancher/wrangler/pkg/signals"
|
|
|
|
"github.com/urfave/cli"
|
2022-02-25 21:00:00 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
2021-01-21 21:09:15 +00:00
|
|
|
)
|
|
|
|
|
2021-05-07 23:10:04 +00:00
|
|
|
// commandSetup setups up common things needed
|
|
|
|
// for each etcd command.
|
2022-03-01 21:33:01 +00:00
|
|
|
func commandSetup(app *cli.Context, cfg *cmds.Server, sc *server.Config) error {
|
2021-05-07 23:10:04 +00:00
|
|
|
gspt.SetProcTitle(os.Args[0])
|
|
|
|
|
|
|
|
nodeName := app.String("node-name")
|
|
|
|
if nodeName == "" {
|
|
|
|
h, err := os.Hostname()
|
|
|
|
if err != nil {
|
2022-03-01 21:33:01 +00:00
|
|
|
return err
|
2021-05-07 23:10:04 +00:00
|
|
|
}
|
|
|
|
nodeName = h
|
|
|
|
}
|
|
|
|
|
|
|
|
os.Setenv("NODE_NAME", nodeName)
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
dataDir, err := server.ResolveDataDir(cfg.DataDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-05-11 23:59:33 +00:00
|
|
|
sc.DisableAgent = true
|
2022-03-01 21:33:01 +00:00
|
|
|
sc.ControlConfig.DataDir = dataDir
|
2021-05-11 23:59:33 +00:00
|
|
|
sc.ControlConfig.EtcdSnapshotName = cfg.EtcdSnapshotName
|
|
|
|
sc.ControlConfig.EtcdSnapshotDir = cfg.EtcdSnapshotDir
|
2022-01-14 17:31:22 +00:00
|
|
|
sc.ControlConfig.EtcdSnapshotCompress = cfg.EtcdSnapshotCompress
|
2022-02-25 21:00:00 +00:00
|
|
|
sc.ControlConfig.EtcdListFormat = strings.ToLower(cfg.EtcdListFormat)
|
2021-05-11 23:59:33 +00:00
|
|
|
sc.ControlConfig.EtcdS3 = cfg.EtcdS3
|
|
|
|
sc.ControlConfig.EtcdS3Endpoint = cfg.EtcdS3Endpoint
|
|
|
|
sc.ControlConfig.EtcdS3EndpointCA = cfg.EtcdS3EndpointCA
|
|
|
|
sc.ControlConfig.EtcdS3SkipSSLVerify = cfg.EtcdS3SkipSSLVerify
|
|
|
|
sc.ControlConfig.EtcdS3AccessKey = cfg.EtcdS3AccessKey
|
|
|
|
sc.ControlConfig.EtcdS3SecretKey = cfg.EtcdS3SecretKey
|
|
|
|
sc.ControlConfig.EtcdS3BucketName = cfg.EtcdS3BucketName
|
|
|
|
sc.ControlConfig.EtcdS3Region = cfg.EtcdS3Region
|
|
|
|
sc.ControlConfig.EtcdS3Folder = cfg.EtcdS3Folder
|
2021-09-05 15:56:15 +00:00
|
|
|
sc.ControlConfig.EtcdS3Insecure = cfg.EtcdS3Insecure
|
2021-10-15 17:24:14 +00:00
|
|
|
sc.ControlConfig.EtcdS3Timeout = cfg.EtcdS3Timeout
|
2021-05-11 23:59:33 +00:00
|
|
|
sc.ControlConfig.Runtime = &config.ControlRuntime{}
|
2022-03-01 21:33:01 +00:00
|
|
|
sc.ControlConfig.Runtime.ETCDServerCA = filepath.Join(dataDir, "tls", "etcd", "server-ca.crt")
|
|
|
|
sc.ControlConfig.Runtime.ClientETCDCert = filepath.Join(dataDir, "tls", "etcd", "client.crt")
|
|
|
|
sc.ControlConfig.Runtime.ClientETCDKey = filepath.Join(dataDir, "tls", "etcd", "client.key")
|
|
|
|
sc.ControlConfig.Runtime.KubeConfigAdmin = filepath.Join(dataDir, "cred", "admin.kubeconfig")
|
2021-05-11 23:59:33 +00:00
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
return nil
|
2021-05-07 23:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
// Run is an alias for Save, retained for compatibility reasons.
|
2021-01-21 21:09:15 +00:00
|
|
|
func Run(app *cli.Context) error {
|
2022-03-01 21:33:01 +00:00
|
|
|
return Save(app)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save triggers an on-demand etcd snapshot operation
|
|
|
|
func Save(app *cli.Context) error {
|
2021-01-21 21:09:15 +00:00
|
|
|
if err := cmds.InitLogging(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-03-01 21:33:01 +00:00
|
|
|
return save(app, &cmds.ServerConfig)
|
2021-01-21 21:09:15 +00:00
|
|
|
}
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
func save(app *cli.Context, cfg *cmds.Server) error {
|
2021-05-11 23:59:33 +00:00
|
|
|
var serverConfig server.Config
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
if err := commandSetup(app, cfg, &serverConfig); err != nil {
|
2021-01-21 21:09:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-05-07 23:10:04 +00:00
|
|
|
if len(app.Args()) > 0 {
|
2021-06-01 19:29:46 +00:00
|
|
|
return util2.ErrCommandNoArgs
|
2021-05-01 01:26:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 21:09:15 +00:00
|
|
|
serverConfig.ControlConfig.EtcdSnapshotRetention = 0 // disable retention check
|
|
|
|
|
2021-11-08 15:32:43 +00:00
|
|
|
ctx := signals.SetupSignalContext()
|
2021-05-07 23:10:04 +00:00
|
|
|
e := etcd.NewETCD()
|
2022-02-24 22:35:08 +00:00
|
|
|
if err := e.SetControlConfig(ctx, &serverConfig.ControlConfig); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-01-21 21:09:15 +00:00
|
|
|
|
2021-05-07 23:10:04 +00:00
|
|
|
initialized, err := e.IsInitialized(ctx, &serverConfig.ControlConfig)
|
2021-01-21 21:09:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !initialized {
|
2022-03-01 21:33:01 +00:00
|
|
|
return fmt.Errorf("etcd database not found in %s", serverConfig.ControlConfig.DataDir)
|
2021-01-21 21:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cluster := cluster.New(&serverConfig.ControlConfig)
|
|
|
|
|
2021-11-10 12:33:42 +00:00
|
|
|
if err := cluster.Bootstrap(ctx, true); err != nil {
|
2021-01-21 21:09:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-05-01 01:26:39 +00:00
|
|
|
sc, err := server.NewContext(ctx, serverConfig.ControlConfig.Runtime.KubeConfigAdmin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
serverConfig.ControlConfig.Runtime.Core = sc.Core
|
|
|
|
|
2021-01-21 21:09:15 +00:00
|
|
|
return cluster.Snapshot(ctx, &serverConfig.ControlConfig)
|
|
|
|
}
|
2021-05-07 23:10:04 +00:00
|
|
|
|
|
|
|
func Delete(app *cli.Context) error {
|
|
|
|
if err := cmds.InitLogging(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return delete(app, &cmds.ServerConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
func delete(app *cli.Context, cfg *cmds.Server) error {
|
2021-05-11 23:59:33 +00:00
|
|
|
var serverConfig server.Config
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
if err := commandSetup(app, cfg, &serverConfig); err != nil {
|
2021-05-07 23:10:04 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
snapshots := app.Args()
|
|
|
|
if len(snapshots) == 0 {
|
|
|
|
return errors.New("no snapshots given for removal")
|
|
|
|
}
|
|
|
|
|
2021-11-08 15:32:43 +00:00
|
|
|
ctx := signals.SetupSignalContext()
|
2021-05-07 23:10:04 +00:00
|
|
|
e := etcd.NewETCD()
|
2022-02-24 22:35:08 +00:00
|
|
|
if err := e.SetControlConfig(ctx, &serverConfig.ControlConfig); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-07 23:10:04 +00:00
|
|
|
|
|
|
|
sc, err := server.NewContext(ctx, serverConfig.ControlConfig.Runtime.KubeConfigAdmin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
serverConfig.ControlConfig.Runtime.Core = sc.Core
|
|
|
|
|
|
|
|
return e.DeleteSnapshots(ctx, app.Args())
|
|
|
|
}
|
2021-05-11 23:59:33 +00:00
|
|
|
|
|
|
|
func List(app *cli.Context) error {
|
|
|
|
if err := cmds.InitLogging(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return list(app, &cmds.ServerConfig)
|
|
|
|
}
|
|
|
|
|
2022-02-25 21:00:00 +00:00
|
|
|
var etcdListFormats = []string{"json", "yaml"}
|
|
|
|
|
|
|
|
func validEtcdListFormat(format string) bool {
|
|
|
|
for _, supportedFormat := range etcdListFormats {
|
|
|
|
if format == supportedFormat {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-05-11 23:59:33 +00:00
|
|
|
func list(app *cli.Context, cfg *cmds.Server) error {
|
|
|
|
var serverConfig server.Config
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
if err := commandSetup(app, cfg, &serverConfig); err != nil {
|
2021-05-11 23:59:33 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-08 15:32:43 +00:00
|
|
|
ctx := signals.SetupSignalContext()
|
2021-05-11 23:59:33 +00:00
|
|
|
e := etcd.NewETCD()
|
2022-02-24 22:35:08 +00:00
|
|
|
if err := e.SetControlConfig(ctx, &serverConfig.ControlConfig); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-11 23:59:33 +00:00
|
|
|
|
|
|
|
sf, err := e.ListSnapshots(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-02-25 21:00:00 +00:00
|
|
|
if cfg.EtcdListFormat != "" && !validEtcdListFormat(cfg.EtcdListFormat) {
|
|
|
|
return errors.New("invalid output format: " + cfg.EtcdListFormat)
|
|
|
|
}
|
2021-05-11 23:59:33 +00:00
|
|
|
|
2022-02-25 21:00:00 +00:00
|
|
|
switch cfg.EtcdListFormat {
|
|
|
|
case "json":
|
|
|
|
if err := json.NewEncoder(os.Stdout).Encode(sf); err != nil {
|
|
|
|
return err
|
2021-11-29 18:30:04 +00:00
|
|
|
}
|
2022-02-25 21:00:00 +00:00
|
|
|
return nil
|
|
|
|
case "yaml":
|
|
|
|
if err := yaml.NewEncoder(os.Stdout).Encode(sf); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
|
|
|
|
defer w.Flush()
|
|
|
|
|
|
|
|
if cfg.EtcdS3 {
|
|
|
|
fmt.Fprint(w, "Name\tSize\tCreated\n")
|
|
|
|
for _, s := range sf {
|
|
|
|
if s.NodeName == "s3" {
|
|
|
|
fmt.Fprintf(w, "%s\t%d\t%s\n", s.Name, s.Size, s.CreatedAt.Format(time.RFC3339))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Fprint(w, "Name\tLocation\tSize\tCreated\n")
|
|
|
|
for _, s := range sf {
|
|
|
|
if s.NodeName != "s3" {
|
|
|
|
fmt.Fprintf(w, "%s\t%s\t%d\t%s\n", s.Name, s.Location, s.Size, s.CreatedAt.Format(time.RFC3339))
|
|
|
|
}
|
2021-11-29 18:30:04 +00:00
|
|
|
}
|
2021-05-11 23:59:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-05-13 20:36:33 +00:00
|
|
|
|
|
|
|
func Prune(app *cli.Context) error {
|
|
|
|
if err := cmds.InitLogging(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return prune(app, &cmds.ServerConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
func prune(app *cli.Context, cfg *cmds.Server) error {
|
|
|
|
var serverConfig server.Config
|
|
|
|
|
2022-03-01 21:33:01 +00:00
|
|
|
if err := commandSetup(app, cfg, &serverConfig); err != nil {
|
2021-05-13 20:36:33 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
serverConfig.ControlConfig.EtcdSnapshotRetention = cfg.EtcdSnapshotRetention
|
|
|
|
|
2021-11-08 15:32:43 +00:00
|
|
|
ctx := signals.SetupSignalContext()
|
2021-05-13 20:36:33 +00:00
|
|
|
e := etcd.NewETCD()
|
2022-02-24 22:35:08 +00:00
|
|
|
if err := e.SetControlConfig(ctx, &serverConfig.ControlConfig); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-13 20:36:33 +00:00
|
|
|
|
2021-11-29 18:30:04 +00:00
|
|
|
sc, err := server.NewContext(ctx, serverConfig.ControlConfig.Runtime.KubeConfigAdmin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
serverConfig.ControlConfig.Runtime.Core = sc.Core
|
|
|
|
|
2021-05-13 20:36:33 +00:00
|
|
|
return e.PruneSnapshots(ctx)
|
|
|
|
}
|