fail,pause,resume commands

This commit is contained in:
Alex Dadgar 2017-06-30 14:27:13 -07:00
parent e7034691ea
commit 58426f0055
8 changed files with 413 additions and 1 deletions

105
command/deployment_fail.go Normal file
View File

@ -0,0 +1,105 @@
package command
import (
"fmt"
"strings"
)
type DeploymentFailCommand struct {
Meta
}
func (c *DeploymentFailCommand) Help() string {
helpText := `
Usage: nomad deployment fail [options] <deployment id>
Fail is used to mark a deployment as failed. Failing a deployment will
stop the placement of new allocations as part of rolling deployment and
if the job is configured to auto revert, the job will attempt to roll back to a
stable version.
General Options:
` + generalOptionsUsage() + `
Fail Options:
-detach
Return immediately instead of entering monitor mode. After deployment
resume, the evaluation ID will be printed to the screen, which can be used
to examine the evaluation using the eval-status command.
-verbose
Display full information.
`
return strings.TrimSpace(helpText)
}
func (c *DeploymentFailCommand) Synopsis() string {
return "Manually fail a deployment"
}
func (c *DeploymentFailCommand) Run(args []string) int {
var detach, verbose bool
flags := c.Meta.FlagSet("deployment resume", FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&detach, "detach", false, "")
flags.BoolVar(&verbose, "verbose", false, "")
if err := flags.Parse(args); err != nil {
return 1
}
// Check that we got no arguments
args = flags.Args()
if l := len(args); l != 1 {
c.Ui.Error(c.Help())
return 1
}
dID := args[0]
// Truncate the id unless full length is requested
length := shortId
if verbose {
length = fullId
}
// Get the HTTP client
client, err := c.Meta.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}
// Do a prefix lookup
deploy, possible, err := getDeployment(client.Deployments(), dID)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error retrieving deployment: %s", err))
return 1
}
if len(possible) != 0 {
c.Ui.Output(fmt.Sprintf("Prefix matched multiple deployments\n\n%s", formatDeployments(possible, length)))
return 0
}
u, _, err := client.Deployments().Fail(deploy.ID, nil)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error failing deployment: %s", err))
return 1
}
c.Ui.Output(fmt.Sprintf("Deployment %q failed", deploy.ID))
evalCreated := u.EvalID != ""
// Nothing to do
if detach || !evalCreated {
return 0
}
c.Ui.Output("")
mon := newMonitor(c.Ui, client, length)
return mon.monitor(u.EvalID, false)
}

View File

@ -0,0 +1,34 @@
package command
import (
"strings"
"testing"
"github.com/mitchellh/cli"
)
func TestDeploymentFailCommand_Implements(t *testing.T) {
var _ cli.Command = &DeploymentFailCommand{}
}
func TestDeploymentFailCommand_Fails(t *testing.T) {
ui := new(cli.MockUi)
cmd := &DeploymentFailCommand{Meta: Meta{Ui: ui}}
// Fails on misuse
if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, cmd.Help()) {
t.Fatalf("expected help output, got: %s", out)
}
ui.ErrorWriter.Reset()
if code := cmd.Run([]string{"-address=nope", "12"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error retrieving deployment") {
t.Fatalf("expected failed query error, got: %s", out)
}
ui.ErrorWriter.Reset()
}

View File

@ -0,0 +1,87 @@
package command
import (
"fmt"
"strings"
)
type DeploymentPauseCommand struct {
Meta
}
func (c *DeploymentPauseCommand) Help() string {
helpText := `
Usage: nomad deployment pause [options] <deployment id>
Pause is used to pause a deployment. Pausing a deployment will pause the
placement of new allocations as part of rolling deployment.
General Options:
` + generalOptionsUsage() + `
Pause Options:
-verbose
Display full information.
`
return strings.TrimSpace(helpText)
}
func (c *DeploymentPauseCommand) Synopsis() string {
return "Pause a deployment"
}
func (c *DeploymentPauseCommand) Run(args []string) int {
var verbose bool
flags := c.Meta.FlagSet("deployment pause", FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&verbose, "verbose", false, "")
if err := flags.Parse(args); err != nil {
return 1
}
// Check that we got no arguments
args = flags.Args()
if l := len(args); l != 1 {
c.Ui.Error(c.Help())
return 1
}
dID := args[0]
// Truncate the id unless full length is requested
length := shortId
if verbose {
length = fullId
}
// Get the HTTP client
client, err := c.Meta.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}
// Do a prefix lookup
deploy, possible, err := getDeployment(client.Deployments(), dID)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error retrieving deployment: %s", err))
return 1
}
if len(possible) != 0 {
c.Ui.Output(fmt.Sprintf("Prefix matched multiple deployments\n\n%s", formatDeployments(possible, length)))
return 0
}
if _, _, err := client.Deployments().Pause(deploy.ID, true, nil); err != nil {
c.Ui.Error(fmt.Sprintf("Error pausing deployment: %s", err))
return 1
}
c.Ui.Output(fmt.Sprintf("Deployment %q paused", deploy.ID))
return 0
}

View File

@ -0,0 +1,34 @@
package command
import (
"strings"
"testing"
"github.com/mitchellh/cli"
)
func TestDeploymentPauseCommand_Implements(t *testing.T) {
var _ cli.Command = &DeploymentPauseCommand{}
}
func TestDeploymentPauseCommand_Fails(t *testing.T) {
ui := new(cli.MockUi)
cmd := &DeploymentPauseCommand{Meta: Meta{Ui: ui}}
// Fails on misuse
if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, cmd.Help()) {
t.Fatalf("expected help output, got: %s", out)
}
ui.ErrorWriter.Reset()
if code := cmd.Run([]string{"-address=nope", "12"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error retrieving deployment") {
t.Fatalf("expected failed query error, got: %s", out)
}
ui.ErrorWriter.Reset()
}

View File

@ -0,0 +1,103 @@
package command
import (
"fmt"
"strings"
)
type DeploymentResumeCommand struct {
Meta
}
func (c *DeploymentResumeCommand) Help() string {
helpText := `
Usage: nomad deployment resume [options] <deployment id>
Resume is used to unpause a paused deployment. Resuming a deployment will
resume the placement of new allocations as part of rolling deployment.
General Options:
` + generalOptionsUsage() + `
Resume Options:
-detach
Return immediately instead of entering monitor mode. After deployment
resume, the evaluation ID will be printed to the screen, which can be used
to examine the evaluation using the eval-status command.
-verbose
Display full information.
`
return strings.TrimSpace(helpText)
}
func (c *DeploymentResumeCommand) Synopsis() string {
return "Resume a paused deployment"
}
func (c *DeploymentResumeCommand) Run(args []string) int {
var detach, verbose bool
flags := c.Meta.FlagSet("deployment resume", FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&detach, "detach", false, "")
flags.BoolVar(&verbose, "verbose", false, "")
if err := flags.Parse(args); err != nil {
return 1
}
// Check that we got no arguments
args = flags.Args()
if l := len(args); l != 1 {
c.Ui.Error(c.Help())
return 1
}
dID := args[0]
// Truncate the id unless full length is requested
length := shortId
if verbose {
length = fullId
}
// Get the HTTP client
client, err := c.Meta.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}
// Do a prefix lookup
deploy, possible, err := getDeployment(client.Deployments(), dID)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error retrieving deployment: %s", err))
return 1
}
if len(possible) != 0 {
c.Ui.Output(fmt.Sprintf("Prefix matched multiple deployments\n\n%s", formatDeployments(possible, length)))
return 0
}
u, _, err := client.Deployments().Pause(deploy.ID, false, nil)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error resuming deployment: %s", err))
return 1
}
c.Ui.Output(fmt.Sprintf("Deployment %q resumed", deploy.ID))
evalCreated := u.EvalID != ""
// Nothing to do
if detach || !evalCreated {
return 0
}
c.Ui.Output("")
mon := newMonitor(c.Ui, client, length)
return mon.monitor(u.EvalID, false)
}

View File

@ -0,0 +1,34 @@
package command
import (
"strings"
"testing"
"github.com/mitchellh/cli"
)
func TestDeploymentResumeCommand_Implements(t *testing.T) {
var _ cli.Command = &DeploymentResumeCommand{}
}
func TestDeploymentResumeCommand_Fails(t *testing.T) {
ui := new(cli.MockUi)
cmd := &DeploymentResumeCommand{Meta: Meta{Ui: ui}}
// Fails on misuse
if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, cmd.Help()) {
t.Fatalf("expected help output, got: %s", out)
}
ui.ErrorWriter.Reset()
if code := cmd.Run([]string{"-address=nope", "12"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error retrieving deployment") {
t.Fatalf("expected failed query error, got: %s", out)
}
ui.ErrorWriter.Reset()
}

View File

@ -24,7 +24,7 @@ General Options:
Revert Options:
-detach
Return immediately instead of entering monitor mode. After job dispatch,
Return immediately instead of entering monitor mode. After job revert,
the evaluation ID will be printed to the screen, which can be used to
examine the evaluation using the eval-status command.

View File

@ -59,11 +59,26 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
Meta: meta,
}, nil
},
"deployment fail": func() (cli.Command, error) {
return &command.DeploymentFailCommand{
Meta: meta,
}, nil
},
"deployment list": func() (cli.Command, error) {
return &command.DeploymentListCommand{
Meta: meta,
}, nil
},
"deployment pause": func() (cli.Command, error) {
return &command.DeploymentPauseCommand{
Meta: meta,
}, nil
},
"deployment resume": func() (cli.Command, error) {
return &command.DeploymentResumeCommand{
Meta: meta,
}, nil
},
"deployment status": func() (cli.Command, error) {
return &command.DeploymentStatusCommand{
Meta: meta,