diff --git a/cmd/crictl/container.go b/cmd/crictl/container.go index ca722dc1bf..ad08283aa1 100644 --- a/cmd/crictl/container.go +++ b/cmd/crictl/container.go @@ -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{ @@ -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{ @@ -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 { @@ -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"), }, @@ -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 { @@ -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"), } @@ -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 } } diff --git a/cmd/crictl/image.go b/cmd/crictl/image.go index 67287991a3..a6f0ee5ae6 100644 --- a/cmd/crictl/image.go +++ b/cmd/crictl/image.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/docker/go-units" "github.com/sirupsen/logrus" @@ -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 { @@ -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) } @@ -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, @@ -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 }