Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APPS-9765 Add command to restart apps #1608

Merged
merged 3 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const (
ArgNoPrefix = "no-prefix"
// ArgAppForceRebuild forces a deployment rebuild
ArgAppForceRebuild = "force-rebuild"
// ArgAppComponents is a list of components to restart.
ArgAppComponents = "components"
// ArgAppAlertDestinations is a path to an app alert destination file.
ArgAppAlertDestinations = "app-alert-destinations"
// ArgClusterName is a cluster name argument.
Expand Down
57 changes: 57 additions & 0 deletions commands/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ This permanently deletes the app and all of its associated deployments.`,
AddBoolFlag(deleteApp, doctl.ArgForce, doctl.ArgShortForce, false, "Delete the App without a confirmation prompt")
deleteApp.Example = `The following example deletes an app with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + `: doctl apps delete f81d4fae-7dec-11d0-a765-00a0c91e6bf6`

restartApp := CmdBuilder(
cmd,
RunAppsRestart,
"restart <app id>",
"Restarts an app",
`Restarts the specified app or some of its components.`,
Writer,
aliasOpt("r"),
displayerType(&displayers.Deployments{}),
)
AddStringSliceFlag(restartApp, doctl.ArgAppComponents, "", nil, "The components to restart. If not provided, all components are restarted.")
AddBoolFlag(restartApp, doctl.ArgCommandWait, "", false,
"Boolean that specifies whether to wait for the restart to complete before allowing further terminal input. This can be helpful for scripting.")
restartApp.Example = `The following example restarts an app with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + `. Additionally, the command returns the app's ID and status: doctl apps restart f81d4fae-7dec-11d0-a765-00a0c91e6bf6 --format ID,Status`

deploymentCreate := CmdBuilder(
cmd,
RunAppsCreateDeployment,
Expand Down Expand Up @@ -469,6 +484,48 @@ func RunAppsDelete(c *CmdConfig) error {
return nil
}

// RunAppsRestart restarts an app.
func RunAppsRestart(c *CmdConfig) error {
if len(c.Args) < 1 {
return doctl.NewMissingArgsErr(c.NS)
}
appID := c.Args[0]
components, err := c.Doit.GetStringSlice(c.NS, doctl.ArgAppComponents)
if err != nil {
return err
}

wait, err := c.Doit.GetBool(c.NS, doctl.ArgCommandWait)
if err != nil {
return err
}

deployment, err := c.Apps().Restart(appID, components)
if err != nil {
return err
}

var errs error

if wait {
apps := c.Apps()
notice("Restart is in progress, waiting for the restart to complete")
err := waitForActiveDeployment(apps, appID, deployment.ID)
if err != nil {
errs = multierror.Append(errs, fmt.Errorf("app deployment couldn't enter `running` state: %v", err))
if err := c.Display(displayers.Deployments{deployment}); err != nil {
errs = multierror.Append(errs, err)
}
return errs
}
deployment, _ = c.Apps().GetDeployment(appID, deployment.ID)
}

notice("Restarted")

return c.Display(displayers.Deployments{deployment})
}

// RunAppsCreateDeployment creates a deployment for an app.
func RunAppsCreateDeployment(c *CmdConfig) error {
if len(c.Args) < 1 {
Expand Down
105 changes: 105 additions & 0 deletions commands/apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestAppsCommand(t *testing.T) {
"list-regions",
"logs",
"propose",
"restart",
"spec",
"tier",
"list-alerts",
Expand Down Expand Up @@ -344,6 +345,110 @@ func TestRunAppsCreateDeploymentWithWait(t *testing.T) {
})
}

func TestRunAppsRestart(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
deployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_PendingDeploy,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 0,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

tm.apps.EXPECT().Restart(appID, []string{"component1", "component2"}).Times(1).Return(deployment, nil)

config.Args = append(config.Args, appID)
config.Doit.Set(config.NS, doctl.ArgAppComponents, []string{"component1", "component2"})

err := RunAppsRestart(config)
require.NoError(t, err)
})
}

func TestRunAppsRestartWithWait(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
deployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_PendingDeploy,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 0,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
activeDeployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_Active,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 1,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

tm.apps.EXPECT().Restart(appID, nil).Times(1).Return(deployment, nil)
tm.apps.EXPECT().GetDeployment(appID, deployment.ID).Times(2).Return(activeDeployment, nil)

config.Args = append(config.Args, appID)
config.Doit.Set(config.NS, doctl.ArgCommandWait, true)

err := RunAppsRestart(config)
require.NoError(t, err)
})
}

func TestRunAppsGetDeployment(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
Expand Down
11 changes: 11 additions & 0 deletions do/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type AppsService interface {
Delete(appID string) error
Propose(req *godo.AppProposeRequest) (*godo.AppProposeResponse, error)

Restart(appID string, components []string) (*godo.Deployment, error)
CreateDeployment(appID string, forceRebuild bool) (*godo.Deployment, error)
GetDeployment(appID, deploymentID string) (*godo.Deployment, error)
ListDeployments(appID string) ([]*godo.Deployment, error)
Expand Down Expand Up @@ -132,6 +133,16 @@ func (s *appsService) Propose(req *godo.AppProposeRequest) (*godo.AppProposeResp
return res, nil
}

func (s *appsService) Restart(appID string, components []string) (*godo.Deployment, error) {
deployment, _, err := s.client.Apps.Restart(s.ctx, appID, &godo.AppRestartRequest{
Components: components,
})
if err != nil {
return nil, err
}
return deployment, nil
}

func (s *appsService) CreateDeployment(appID string, forceRebuild bool) (*godo.Deployment, error) {
deployment, _, err := s.client.Apps.CreateDeployment(s.ctx, appID, &godo.DeploymentCreateRequest{
ForceBuild: forceRebuild,
Expand Down
15 changes: 15 additions & 0 deletions do/mocks/AppsService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22
require (
github.com/blang/semver v3.5.1+incompatible
github.com/creack/pty v1.1.21
github.com/digitalocean/godo v1.130.0
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd
github.com/docker/cli v24.0.5+incompatible
github.com/docker/docker v25.0.6+incompatible
github.com/docker/docker-credential-helpers v0.7.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/digitalocean/godo v1.130.0 h1:DbJg0wvBxTkYjY5Q9S1mwzAZLd5Wht3r57yFH4yeMCk=
github.com/digitalocean/godo v1.130.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd h1:3TCd+SNAbaRHQSiWmMJWtPitvZt2lTq3th87CxMl9Xo=
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
Expand Down
4 changes: 2 additions & 2 deletions vendor/github.com/digitalocean/godo/apps.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions vendor/github.com/digitalocean/godo/apps.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ github.com/creack/pty
# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
## explicit
github.com/davecgh/go-spew/spew
# github.com/digitalocean/godo v1.130.0
# github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd
## explicit; go 1.22
github.com/digitalocean/godo
github.com/digitalocean/godo/metrics
Expand Down
Loading