Skip to content

Commit

Permalink
feat(CLI): Add pause and resume (#228)
Browse files Browse the repository at this point in the history
* feat(CLI): Add pause and resume

Signed-off-by: Ce Gao <cegao@tensorchord.ai>

* fix: Use crdb errors

Signed-off-by: Ce Gao <cegao@tensorchord.ai>
  • Loading branch information
gaocegege authored Jun 1, 2022
1 parent 3184df9 commit 31514df
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 5 deletions.
2 changes: 1 addition & 1 deletion cmd/envd/get_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func renderEnvironments(envs []types.EnvdEnvironment, w io.Writer) {
envRow[5] = strconv.FormatBool(env.GPU)
envRow[6] = stringOrNone(env.CUDA)
envRow[7] = stringOrNone(env.CUDNN)
envRow[8] = env.State
envRow[8] = env.Status
envRow[9] = stringid.TruncateID(env.Container.ID)
table.Append(envRow)
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/envd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func run(args []string) (bool, error) {
CommandBuild,
CommandDestroy,
CommandGet,
CommandPause,
CommandResume,
CommandUp,
}

Expand Down
54 changes: 54 additions & 0 deletions cmd/envd/pause.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2022 The envd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/cockroachdb/errors"
"github.com/sirupsen/logrus"
"github.com/tensorchord/envd/pkg/envd"
"github.com/urfave/cli/v2"
)

var CommandPause = &cli.Command{
Name: "pause",
Aliases: []string{"p"},
Usage: "pause the envd environment",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "env",
Usage: "environment name",
Aliases: []string{"e"},
},
},

Action: pause,
}

func pause(clicontext *cli.Context) error {
env := clicontext.String("env")
if env == "" {
return errors.New("env is required")
}
envdEngine, err := envd.New(clicontext.Context)
if err != nil {
return errors.Wrap(err, "failed to create envd engine")
}
if name, err := envdEngine.PauseEnvironment(clicontext.Context, env); err != nil {
return errors.Wrap(err, "failed to pause the environment")
} else if name != "" {
logrus.Infof("%s is paused", name)
}
return nil
}
54 changes: 54 additions & 0 deletions cmd/envd/resume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2022 The envd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/cockroachdb/errors"
"github.com/sirupsen/logrus"
"github.com/tensorchord/envd/pkg/envd"
"github.com/urfave/cli/v2"
)

var CommandResume = &cli.Command{
Name: "resume",
Aliases: []string{"r"},
Usage: "resume the envd environment",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "env",
Usage: "environment name",
Aliases: []string{"e"},
},
},

Action: resume,
}

func resume(clicontext *cli.Context) error {
env := clicontext.String("env")
if env == "" {
return errors.New("env is required")
}
envdEngine, err := envd.New(clicontext.Context)
if err != nil {
return errors.Wrap(err, "failed to create envd engine")
}
if name, err := envdEngine.ResumeEnvironment(clicontext.Context, env); err != nil {
return errors.Wrap(err, "failed to pause the environment")
} else if name != "" {
logrus.Infof("%s is resumed", name)
}
return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ require (
github.com/onsi/gomega v1.19.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.4
github.com/sirupsen/logrus v1.8.1
github.com/spf13/viper v1.4.0
Expand Down Expand Up @@ -83,6 +82,7 @@ require (
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/moby/sys/signal v0.6.0 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand Down
40 changes: 40 additions & 0 deletions pkg/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type Client interface {

ListContainer(ctx context.Context) ([]types.Container, error)
GetContainer(ctx context.Context, cname string) (types.ContainerJSON, error)
PauseContainer(ctx context.Context, name string) (string, error)
ResumeContainer(ctx context.Context, name string) (string, error)

ListImage(ctx context.Context) ([]types.ImageSummary, error)
GetImage(ctx context.Context, image string) (types.ImageSummary, error)
Expand Down Expand Up @@ -156,6 +158,44 @@ func (c generalClient) ListContainer(ctx context.Context) ([]types.Container, er
return ctrs, nil
}

func (c generalClient) PauseContainer(ctx context.Context, name string) (string, error) {
logger := logrus.WithField("container", name)
err := c.ContainerPause(ctx, name)
if err != nil {
errCause := errors.UnwrapAll(err).Error()
switch {
case strings.Contains(errCause, "is already paused"):
logger.Debug("container is already paused, there is no need to pause it again")
return "", nil
case strings.Contains(errCause, "No such container"):
logger.Debug("container is not found, there is no need to pause it")
return "", errors.New("container not found")
default:
return "", errors.Wrap(err, "failed to pause container")
}
}
return name, nil
}

func (c generalClient) ResumeContainer(ctx context.Context, name string) (string, error) {
logger := logrus.WithField("container", name)
err := c.ContainerUnpause(ctx, name)
if err != nil {
errCause := errors.UnwrapAll(err).Error()
switch {
case strings.Contains(errCause, "is not paused"):
logger.Debug("container is not paused, there is no need to resume")
return "", nil
case strings.Contains(errCause, "No such container"):
logger.Debug("container is not found, there is no need to resume it")
return "", errors.New("container not found")
default:
return "", errors.Wrap(err, "failed to resume container")
}
}
return name, nil
}

func (c generalClient) GetContainer(ctx context.Context, cname string) (types.ContainerJSON, error) {
return c.ContainerInspect(ctx, cname)
}
Expand Down
27 changes: 27 additions & 0 deletions pkg/envd/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import (
type Engine interface {
ListImage(ctx context.Context) ([]types.EnvdImage, error)
ListImageDependency(ctx context.Context, image string) (*types.Dependency, error)

PauseEnvironment(ctx context.Context, env string) (string, error)
ResumeEnvironment(ctx context.Context, env string) (string, error)
ListEnvironment(ctx context.Context) ([]types.EnvdEnvironment, error)
ListEnvDependency(ctx context.Context, env string) (*types.Dependency, error)
ListEnvFullDependency(ctx context.Context, env, SSHKeyPath string) (string, error)
Expand Down Expand Up @@ -79,6 +82,30 @@ func (e generalEngine) ListEnvironment(
return envs, nil
}

func (e generalEngine) PauseEnvironment(ctx context.Context, env string) (string, error) {
logger := logrus.WithFields(logrus.Fields{
"env": env,
})
logger.Debug("pausing environment")
name, err := e.dockerCli.PauseContainer(ctx, env)
if err != nil {
return "", errors.Wrap(err, "failed to pause the environment")
}
return name, nil
}

func (e generalEngine) ResumeEnvironment(ctx context.Context, env string) (string, error) {
logger := logrus.WithFields(logrus.Fields{
"env": env,
})
logger.Debug("resuming environment")
name, err := e.dockerCli.ResumeContainer(ctx, env)
if err != nil {
return "", errors.Wrap(err, "failed to resume the environment")
}
return name, nil
}

// ListEnvDependency gets the dependencies of the given environment.
func (e generalEngine) ListImageDependency(
ctx context.Context, image string) (*types.Dependency, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/lang/frontend/starlark/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
package starlark

import (
"github.com/pkg/errors"
"github.com/cockroachdb/errors"
"github.com/sirupsen/logrus"
"go.starlark.net/repl"
"go.starlark.net/starlark"
Expand Down
2 changes: 1 addition & 1 deletion pkg/progress/progresswriter/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import (
"context"
"os"

"github.com/cockroachdb/errors"
"github.com/containerd/console"
"github.com/moby/buildkit/client"
"github.com/pkg/errors"

"github.com/tensorchord/envd/pkg/progress/progressui"
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/shell/zsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
_ "embed"
"path/filepath"

"github.com/cockroachdb/errors"
"github.com/go-git/go-git/v5"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tensorchord/envd/pkg/home"
"github.com/tensorchord/envd/pkg/util/fileutil"
Expand Down

0 comments on commit 31514df

Please sign in to comment.