Skip to content

Commit

Permalink
Add --pull-timeout flag to crictl create, run and pull comm…
Browse files Browse the repository at this point in the history
…ands

This allows to set a pull context timeout for the supported commands.
Runtimes may or may not use the timeout from the RPC for image pulls,
but `crictl` should generally support that feature.

Signed-off-by: Sascha Grunert <[email protected]>
  • Loading branch information
saschagrunert committed Jun 6, 2024
1 parent 6c92933 commit ac5230a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 18 deletions.
50 changes: 35 additions & 15 deletions cmd/crictl/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ type pullOptions struct {
// Username to use for accessing the registry
// password will be requested on the command line
username string

// timeout is the maximum time used for the image pull
timeout time.Duration
}

var createPullFlags = []cli.Flag{
Expand All @@ -111,6 +114,17 @@ var createPullFlags = []cli.Flag{
Value: "",
Usage: "Use `USERNAME` for accessing the registry. The password will be requested on the command line",
},
&cli.DurationFlag{
Name: "cancel-timeout",
Aliases: []string{"T"},
Usage: "Seconds to wait for a container create request to complete before cancelling the request",
},
&cli.DurationFlag{
Name: "pull-timeout",
Aliases: []string{"pt"},
Usage: "Maximum time to be used for pulling the image, disabled if set to 0s",
EnvVars: []string{"CRICTL_PULL_TIMEOUT"},
},
}

var runPullFlags = []cli.Flag{
Expand All @@ -137,17 +151,29 @@ var runPullFlags = []cli.Flag{
Value: "",
Usage: "Use `USERNAME` for accessing the registry. password will be requested",
},
&cli.StringFlag{
Name: "runtime",
Aliases: []string{"r"},
Usage: "Runtime handler to use. Available options are defined by the container runtime.",
},
&cli.DurationFlag{
Name: "timeout",
Aliases: []string{"t"},
Usage: "Seconds to wait for a container create request before cancelling the request",
},
&cli.DurationFlag{
Name: "pull-timeout",
Aliases: []string{"pt"},
Usage: "Maximum time to be used for pulling the image, disabled if set to 0s",
EnvVars: []string{"CRICTL_PULL_TIMEOUT"},
},
}

var createContainerCommand = &cli.Command{
Name: "create",
Usage: "Create a new container",
ArgsUsage: "POD container-config.[json|yaml] pod-config.[json|yaml]",
Flags: append(createPullFlags, &cli.DurationFlag{
Name: "cancel-timeout",
Aliases: []string{"T"},
Usage: "Seconds to wait for a container create request to complete before cancelling the request",
}),
Flags: createPullFlags,

Action: func(c *cli.Context) (err error) {
if c.Args().Len() != 3 {
Expand Down Expand Up @@ -177,6 +203,7 @@ var createContainerCommand = &cli.Command{
creds: c.String("creds"),
auth: c.String("auth"),
username: c.String("username"),
timeout: c.Duration("pull-timeout"),
},
timeout: c.Duration("cancel-timeout"),
},
Expand Down Expand Up @@ -581,15 +608,7 @@ var runContainerCommand = &cli.Command{
Name: "run",
Usage: "Run a new container inside a sandbox",
ArgsUsage: "container-config.[json|yaml] pod-config.[json|yaml]",
Flags: append(runPullFlags, &cli.StringFlag{
Name: "runtime",
Aliases: []string{"r"},
Usage: "Runtime handler to use. Available options are defined by the container runtime.",
}, &cli.DurationFlag{
Name: "timeout",
Aliases: []string{"t"},
Usage: "Seconds to wait for a container create request before cancelling the request",
}),
Flags: runPullFlags,

Action: func(c *cli.Context) (err error) {
if c.Args().Len() != 2 {
Expand Down Expand Up @@ -617,6 +636,7 @@ var runContainerCommand = &cli.Command{
creds: c.String("creds"),
auth: c.String("auth"),
username: c.String("username"),
timeout: c.Duration("pull-timeout"),
},
timeout: c.Duration("timeout"),
}
Expand Down Expand Up @@ -747,7 +767,7 @@ func CreateContainer(

// Try to pull the image before container creation
ann := config.GetImage().GetAnnotations()
if _, err := PullImageWithSandbox(iClient, image, auth, podConfig, ann); err != nil {
if _, err := PullImageWithSandbox(iClient, image, auth, podConfig, ann, opts.pullOptions.timeout); err != nil {
return "", err
}
}
Expand Down
28 changes: 25 additions & 3 deletions cmd/crictl/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"strconv"
"strings"
"syscall"
"time"

"github.com/docker/go-units"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -83,6 +84,12 @@ var pullImageCommand = &cli.Command{
Aliases: []string{"a"},
Usage: "Annotation to be set on the pulled image",
},
&cli.DurationFlag{
Name: "pull-timeout",
Aliases: []string{"pt"},
Usage: "Maximum time to be used for pulling the image, disabled if set to 0s",
EnvVars: []string{"CRICTL_PULL_TIMEOUT"},
},
},
ArgsUsage: "NAME[:TAG|@DIGEST]",
Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -119,7 +126,8 @@ var pullImageCommand = &cli.Command{
return err
}
}
r, err := PullImageWithSandbox(imageClient, imageName, auth, sandbox, ann)
timeout := c.Duration("timeout")
r, err := PullImageWithSandbox(imageClient, imageName, auth, sandbox, ann, timeout)
if err != nil {
return fmt.Errorf("pulling image: %w", err)
}
Expand Down Expand Up @@ -633,7 +641,7 @@ func normalizeRepoDigest(repoDigests []string) (string, string) {

// PullImageWithSandbox sends a PullImageRequest to the server, and parses
// the returned PullImageResponse.
func PullImageWithSandbox(client internalapi.ImageManagerService, image string, auth *pb.AuthConfig, sandbox *pb.PodSandboxConfig, ann map[string]string) (*pb.PullImageResponse, error) {
func PullImageWithSandbox(client internalapi.ImageManagerService, image string, auth *pb.AuthConfig, sandbox *pb.PodSandboxConfig, ann map[string]string, timeout time.Duration) (*pb.PullImageResponse, error) {
request := &pb.PullImageRequest{
Image: &pb.ImageSpec{
Image: image,
Expand All @@ -647,7 +655,21 @@ func PullImageWithSandbox(client internalapi.ImageManagerService, image string,
request.SandboxConfig = sandbox
}
logrus.Debugf("PullImageRequest: %v", request)
res, err := client.PullImage(context.TODO(), request.Image, request.Auth, request.SandboxConfig)

if timeout < 0 {
return nil, errors.New("timeout should be bigger than 0")
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if timeout > 0 {
logrus.Debugf("Using context with timeout of %s", timeout)
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
}

res, err := client.PullImage(ctx, request.Image, request.Auth, request.SandboxConfig)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit ac5230a

Please sign in to comment.