Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

feature: Waypoint Server Upgrade command for supported server platforms #976

Merged
merged 59 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
7e55269
internal/serverinstall: Server upgrades for supported platforms
briancain Dec 8, 2020
f82e525
Use exec for kubectl set image on upgrades
briancain Jan 12, 2021
f794814
Remove unused flags
briancain Jan 13, 2021
1ee6011
Reorganize Upgrade k8s func
briancain Jan 13, 2021
c63eff7
Replace removed cli flag with actual value
briancain Jan 13, 2021
a25df0d
Add pod deletion in the case of OnDelete update strategy
briancain Jan 13, 2021
9909dc1
Add note about RollingUpdates for k8s upgrades
briancain Jan 13, 2021
306b4b6
Improve RollingUpdate upgrade note for k8s
briancain Jan 13, 2021
9385246
Add extra warnings around server snapshots before upgrades
briancain Jan 13, 2021
ed0d8da
Align upgrade help text
briancain Jan 13, 2021
1a9071f
Delete extra spaces
briancain Jan 13, 2021
846f9fe
Remove unused func;
briancain Jan 13, 2021
9712fca
Update comment about obtaining waypoint container in docker
briancain Jan 13, 2021
cde376f
Remove old TODO
briancain Jan 13, 2021
d8c392e
Use vars for setting listen ports
briancain Jan 13, 2021
15ce533
Move upgrade func next to install func in dockerr platform
briancain Jan 13, 2021
56c0b15
Update todo
briancain Jan 13, 2021
ae82fc3
Add docs for upgrade command guide
briancain Jan 13, 2021
5fe56e7
Add more content to server upgrade command page
briancain Jan 13, 2021
409e920
Fix layout format
briancain Jan 13, 2021
6d96b57
Generate website command docs
briancain Jan 13, 2021
eb23072
Remove TODO
briancain Jan 13, 2021
43e8ec7
Use default serverName and serviceName
briancain Jan 14, 2021
0beba6d
Update internal/cli/server_upgrade.go
briancain Jan 14, 2021
75668f7
Update internal/serverinstall/k8s.go
briancain Jan 14, 2021
ae8fdae
Remove initWriter helper and use os.Create directly
briancain Jan 14, 2021
aa9f6de
Update error string
briancain Jan 14, 2021
90af7b9
Add note and move ui output
briancain Jan 14, 2021
23cad96
Only update server context on server address change
briancain Jan 14, 2021
ba4382e
Set a default server image in serverinstall
briancain Jan 14, 2021
318ac12
Always pull on latest server image to ensure latest
briancain Jan 14, 2021
29ca8c9
Update internal/cli/server_upgrade.go
briancain Jan 14, 2021
dff127b
Update internal/serverinstall/k8s.go
briancain Jan 14, 2021
68488cd
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
8436dee
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
a7cb9f0
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
686d297
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
5534ce4
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
eda966c
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
c97106b
Update website/content/docs/upgrading/index.mdx
briancain Jan 14, 2021
21dd26d
Format stepgroup Update method for readability
briancain Jan 14, 2021
310134a
Submit patch to kubernetes to upgrade waypoint server pod container
briancain Jan 15, 2021
3fd7475
Update snapshot-name to show default
briancain Jan 15, 2021
d275019
Add space for help text between new lines
briancain Jan 15, 2021
2a36392
Merge branch 'main' into feat/upgrade-server
briancain Jan 15, 2021
69cda51
Group together install/upgrade/uninstall functions
briancain Jan 15, 2021
4e2849b
Update website docs for server uninstall/upgrade CLIs
briancain Jan 15, 2021
12d28c0
Upgrade uninstall snapshot to match upgrade cli
briancain Jan 19, 2021
48f2bca
Update uninstall cli website docs
briancain Jan 19, 2021
4fed93b
Merge branch 'main' into feat/upgrade-server
briancain Jan 19, 2021
1c96f79
go fmt
briancain Jan 19, 2021
6563e98
Look at job allocations rather than from an evaluation
briancain Jan 20, 2021
7346d91
Add extra output when verifying server connection after upgrades
briancain Jan 20, 2021
ed3e60b
Reduce connection timeout and improve help text for conenct failures
briancain Jan 20, 2021
1500aa5
Add note about URL service re-registering new url on server upgrade
briancain Jan 20, 2021
d71b58f
Remove note about nomad not moving over db from alloc
briancain Jan 20, 2021
bb51191
Increase connect verify timeout to 3 minutes
briancain Jan 20, 2021
ec02469
Update snapshot flag
briancain Jan 21, 2021
bb3f981
Update uninstall and upgrade cli docs
briancain Jan 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/cli/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,6 @@ deployments. If this is incorrect, manually set it using the CLI command
"waypoint server config-set".

Advertise Address: %[2]s
Web UI Address: %[3]s
Web UI Address: %[3]s
`)
)
5 changes: 5 additions & 0 deletions internal/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ func Commands(
baseCommand: baseCommand,
}, nil
},
"server upgrade": func() (cli.Command, error) {
return &ServerUpgradeCommand{
baseCommand: baseCommand,
}, nil
},
"plugin": func() (cli.Command, error) {
return &PluginCommand{
baseCommand: baseCommand,
Expand Down
364 changes: 364 additions & 0 deletions internal/cli/server_upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
package cli

import (
"fmt"
"os"
"strings"
"time"

"github.com/golang/protobuf/ptypes/empty"
"github.com/posener/complete"

"github.com/hashicorp/waypoint-plugin-sdk/terminal"
clientpkg "github.com/hashicorp/waypoint/internal/client"
"github.com/hashicorp/waypoint/internal/clierrors"
"github.com/hashicorp/waypoint/internal/clisnapshot"
"github.com/hashicorp/waypoint/internal/pkg/flag"
pb "github.com/hashicorp/waypoint/internal/server/gen"
"github.com/hashicorp/waypoint/internal/serverclient"
"github.com/hashicorp/waypoint/internal/serverinstall"
)

type ServerUpgradeCommand struct {
*baseCommand

platform string
contextName string
snapshotName string
skipSnapshot bool
confirm bool
}

func (c *ServerUpgradeCommand) Run(args []string) int {
ctx := c.Ctx
log := c.Log.Named("upgrade")
defer c.Close()

// Initialize. If we fail, we just exit since Init handles the UI.
if err := c.Init(
WithArgs(args),
WithFlags(c.Flags()),
WithNoConfig(),
); err != nil {
return 1
}

// Error handling from input

if !c.confirm {
c.ui.Output(confirmReqMsg, terminal.WithErrorStyle())
return 1
}

if c.platform == "" {
c.ui.Output(
"A platform is required and must match the server context",
terminal.WithErrorStyle(),
)
return 1
}

p, ok := serverinstall.Platforms[strings.ToLower(c.platform)]
if !ok {
c.ui.Output(
"Error upgrading server on %s: unsupported platform",
c.platform,
terminal.WithErrorStyle(),
)

return 1
}

// Finish error handling

// Get Server config to preserve existing configurations from context
var ctxName string
if c.contextName != "" {
ctxName = c.contextName
} else {
defaultName, err := c.contextStorage.Default()
if err != nil {
c.ui.Output(
"Error getting default context: %s",
clierrors.Humanize(err),
terminal.WithErrorStyle(),
)
return 1
}
ctxName = defaultName
}

originalCfg, err := c.contextStorage.Load(ctxName)
if err != nil {
c.ui.Output(
"Error loading the context %q: %s",
ctxName,
clierrors.Humanize(err),
terminal.WithErrorStyle(),
)
return 1
}

// Upgrade waypoint server
sg := c.ui.StepGroup()
defer sg.Wait()

s := sg.Add("Validating server context: %q", ctxName)
defer func() { s.Abort() }()

conn, err := serverclient.Connect(ctx, serverclient.FromContextConfig(originalCfg))
if err != nil {
c.ui.Output(
"Error connecting with context %q: %s",
ctxName,
clierrors.Humanize(err),
terminal.WithErrorStyle(),
)
return 1
}

s.Update("Verifying connection is valid for context %q...", ctxName)

client := pb.NewWaypointClient(conn)
// validate API compat here with new clientpkg
if _, err := clientpkg.New(ctx,
briancain marked this conversation as resolved.
Show resolved Hide resolved
clientpkg.WithLogger(c.Log),
clientpkg.WithClient(client),
); err != nil {
c.ui.Output(
"Error connecting with context %q: %s",
ctxName,
clierrors.Humanize(err),
terminal.WithErrorStyle(),
)
return 1
}

resp, err := client.GetVersionInfo(ctx, &empty.Empty{})
if err != nil {
c.ui.Output(
"Error retrieving server version info: %s", clierrors.Humanize(err),
terminal.WithErrorStyle())
return 1
}

initServerVersion := resp.Info.Version

s.Update("Context %q validated and connected successfully.", ctxName)
s.Done()

s = sg.Add("Starting server snapshots")

// Snapshot server before upgrade
if !c.skipSnapshot {
s.Update("Taking server snapshot before upgrading")

snapshotName := c.snapshotName
if c.snapshotName == defaultSnapshotName {
// Append timestamps on default snapshot names
snapshotName = fmt.Sprintf("%s-%d", c.snapshotName, time.Now().Unix())
}

s.Update("Taking snapshot of server with name: '%s'", snapshotName)
writer, err := os.Create(snapshotName)
if err != nil {
s.Update("Failed to take server snapshot")
s.Status(terminal.StatusError)
s.Done()

c.ui.Output(fmt.Sprintf("Error opening output: %s", err), terminal.WithErrorStyle())
return 1
}

err = clisnapshot.WriteSnapshot(c.Ctx, c.project.Client(), writer)
writer.Close()

if err != nil {
s.Update("Failed to take server snapshot")
s.Status(terminal.StatusError)
s.Done()

c.ui.Output(fmt.Sprintf("Error generating Snapshot: %s", err), terminal.WithErrorStyle())
krantzinator marked this conversation as resolved.
Show resolved Hide resolved
return 1
}

s.Update("Snapshot of server written to: '%s'", snapshotName)
s.Done()
} else {
s.Update("Server snapshot disabled on request, this means no snapshot will be taken before upgrades")
s.Status(terminal.StatusWarn)
s.Done()
log.Warn("Server snapshot disabled on request from user, skipping")
}

c.ui.Output("Upgrading...", terminal.WithHeaderStyle())
briancain marked this conversation as resolved.
Show resolved Hide resolved

c.ui.Output("Waypoint server will now upgrade from version %q",
briancain marked this conversation as resolved.
Show resolved Hide resolved
initServerVersion, terminal.WithInfoStyle())

// Upgrade in place
result, err := p.Upgrade(ctx, &serverinstall.InstallOpts{
Log: log,
UI: c.ui,
}, originalCfg.Server)
if err != nil {
c.ui.Output(
"Error upgrading server on %s: %s", c.platform, clierrors.Humanize(err),
terminal.WithErrorStyle())

c.ui.Output(upgradeFailHelp)

return 1
}

contextConfig := result.Context
advertiseAddr := result.AdvertiseAddr
httpAddr := result.HTTPAddr

// We update the context config if the server addr has changed between upgrades
if originalCfg.Server.Address != contextConfig.Server.Address {
originalCfg.Server.Address = contextConfig.Server.Address

if err := c.contextStorage.Set(ctxName, originalCfg); err != nil {
c.ui.Output(
"Error setting the CLI context: %s\n\n%s",
clierrors.Humanize(err),
errInstallRunning,
terminal.WithErrorStyle(),
)
return 1
}

c.ui.Output("Server address has changed after upgrade. This client will "+
"update its context with the new address, however any other clients "+
"using this server must manually update their server address listed below "+
"or find the address from `waypoint context list` which lists context %q address",
ctxName,
terminal.WithWarningStyle())
}

// Connect
log.Info("connecting to the server so we can verify the server upgrade", "addr", originalCfg.Server.Address)
conn, err = serverclient.Connect(ctx,
serverclient.FromContextConfig(originalCfg),
serverclient.Timeout(5*time.Minute),
)
if err != nil {
c.ui.Output(
"Error connecting to server: %s\n\n%s",
clierrors.Humanize(err),
errInstallRunning,
terminal.WithErrorStyle(),
)
return 1
}
client = pb.NewWaypointClient(conn)

resp, err = client.GetVersionInfo(ctx, &empty.Empty{})
briancain marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
c.ui.Output(
"Error retrieving server version info: %s", clierrors.Humanize(err),
terminal.WithErrorStyle())
return 1
}

c.ui.Output("\nServer upgrade for platform %q context %q complete!",
c.platform, ctxName, terminal.WithSuccessStyle())

c.ui.Output("Waypoint has finished upgrading the server to version %q\n",
resp.Info.Version, terminal.WithSuccessStyle())

c.ui.Output(addrSuccess, advertiseAddr.Addr, "https://"+httpAddr,
terminal.WithSuccessStyle())

return 0
}

func (c *ServerUpgradeCommand) Flags() *flag.Sets {
return c.flagSet(0, func(set *flag.Sets) {
f := set.NewSet("Command Options")
f.BoolVar(&flag.BoolVar{
Name: "auto-approve",
Target: &c.confirm,
Default: false,
Usage: "Confirm server upgrade.",
})
f.StringVar(&flag.StringVar{
Name: "context-name",
Target: &c.contextName,
Default: "",
Usage: "Waypoint server context to upgrade.",
})
f.StringVar(&flag.StringVar{
Name: "platform",
Target: &c.platform,
Default: "",
Usage: "Platform to upgrade the Waypoint server from.",
})
f.StringVar(&flag.StringVar{
Name: "snapshot-name",
Target: &c.snapshotName,
Default: defaultSnapshotName,
Usage: "Filename to write the snapshot to. If no name is specified, by" +
" default a timestamp will be appended to the default snapshot name.",
})
f.BoolVar(&flag.BoolVar{
Name: "skip-snapshot",
Target: &c.skipSnapshot,
Default: false,
Usage: "Skip creating a snapshot of the Waypoint server.",
})

for name, platform := range serverinstall.Platforms {
platformSet := set.NewSet(name + " Options")
platform.UpgradeFlags(platformSet)
}
})
}

func (c *ServerUpgradeCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictNothing
}

func (c *ServerUpgradeCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}

func (c *ServerUpgradeCommand) Synopsis() string {
return "Upgrades Waypoint server in the current context to the latest version"
}

func (c *ServerUpgradeCommand) Help() string {
return formatHelp(`
Usage: waypoint server upgrade [options]

Upgrade Waypoint server in the current context to the latest version or the
server image version specified. By default, Waypoint will upgrade to server
version "hashicorp/waypoint:latest". Before upgrading, a snapshot of the
server will be taken in case of any upgrade failures.

` + c.Flags().Help())
}

var (
defaultSnapshotName = "waypoint-server-snapshot"
briancain marked this conversation as resolved.
Show resolved Hide resolved
confirmReqMsg = strings.TrimSpace(`
Upgrading Waypoint server requires confirmation.
Rerun the command with '-auto-approve' to continue with the upgrade.
`)
upgradeFailHelp = strings.TrimSpace(`
Upgrading Waypoint server has failed. To restore from a snapshot, use the command:

waypoint server restore [snapshot-name]

Where 'snapshot-name' is the name of the snapshot taken prior to the upgrade.

More information can be found by runninng 'waypoint server restore -help' or
following the server maintenence guide for backups and restores:
https://www.waypointproject.io/docs/server/run/maintenance#backup-restore
`)
addrSuccess = strings.TrimSpace(`
Advertise Address: %[1]s
Web UI Address: %[2]s
`)
)
Loading