Skip to content

Commit

Permalink
Merge pull request #1462 from saschagrunert/interruptable-image
Browse files Browse the repository at this point in the history
Make image RPCs interruptable using Ctrl-C

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
  • Loading branch information
k8s-ci-robot authored and saschagrunert committed Jun 24, 2024
2 parents 52a3c8b + c6918de commit d8fdb7a
Show file tree
Hide file tree
Showing 11 changed files with 1,861 additions and 851 deletions.
2 changes: 1 addition & 1 deletion cmd/crictl/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,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, opts.pullOptions.timeout); err != nil {
if _, err := PullImageWithSandbox(iClient, image, auth, podConfig, ann, opts.pullOptions.timeout, false, ""); err != nil {
return "", err
}
}
Expand Down
49 changes: 37 additions & 12 deletions cmd/crictl/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ var pullImageCommand = &cli.Command{
Usage: "Maximum time to be used for pulling the image, disabled if set to 0s",
EnvVars: []string{"CRICTL_PULL_TIMEOUT"},
},
&cli.BoolFlag{
Name: "mount",
Aliases: []string{"m"},
Usage: "Mount the OCI object",
},
&cli.StringFlag{
Name: "mount-label",
Aliases: []string{"l"},
Usage: "Mount label for the OCI object",
},
},
ArgsUsage: "NAME[:TAG|@DIGEST]",
Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -127,11 +137,15 @@ var pullImageCommand = &cli.Command{
}
}
timeout := c.Duration("pull-timeout")
r, err := PullImageWithSandbox(imageClient, imageName, auth, sandbox, ann, timeout)
r, err := PullImageWithSandbox(imageClient, imageName, auth, sandbox, ann, timeout, c.Bool("mount"), c.String("mount-label"))
if err != nil {
return fmt.Errorf("pulling image: %w", err)
}
fmt.Printf("Image is up to date for %s\n", r.ImageRef)

if r.Mountpoint != "" {
fmt.Printf("Image mounted to: %s\n", r.Mountpoint)
}
return nil
},
}
Expand Down Expand Up @@ -417,7 +431,9 @@ var removeImageCommand = &cli.Command{
}

// Container images
containers, err := runtimeClient.ListContainers(context.TODO(), nil)
containers, err := InterruptableRPC(nil, func(ctx context.Context) ([]*pb.Container, error) {
return runtimeClient.ListContainers(ctx, nil)
})
if err != nil {
return err
}
Expand Down Expand Up @@ -641,11 +657,13 @@ 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, timeout time.Duration) (*pb.PullImageResponse, error) {
func PullImageWithSandbox(client internalapi.ImageManagerService, image string, auth *pb.AuthConfig, sandbox *pb.PodSandboxConfig, ann map[string]string, timeout time.Duration, mount bool, mountLabel string) (*pb.PullImageResponse, error) {
request := &pb.PullImageRequest{
Image: &pb.ImageSpec{
Image: image,
Annotations: ann,
Mount: mount,
MountLabel: mountLabel,
},
}
if auth != nil {
Expand All @@ -669,11 +687,12 @@ func PullImageWithSandbox(client internalapi.ImageManagerService, image string,
defer cancel()
}

res, err := client.PullImage(ctx, request.Image, request.Auth, request.SandboxConfig)
res, err := InterruptableRPC(ctx, func(ctx context.Context) (string, error) {
return client.PullImage(ctx, request.Image, request.Auth, request.SandboxConfig)
})
if err != nil {
return nil, err
}
resp := &pb.PullImageResponse{ImageRef: res}
logrus.Debugf("PullImageResponse: %v", resp)
return resp, nil
}
Expand All @@ -683,7 +702,9 @@ func PullImageWithSandbox(client internalapi.ImageManagerService, image string,
func ListImages(client internalapi.ImageManagerService, image string) (*pb.ListImagesResponse, error) {
request := &pb.ListImagesRequest{Filter: &pb.ImageFilter{Image: &pb.ImageSpec{Image: image}}}
logrus.Debugf("ListImagesRequest: %v", request)
res, err := client.ListImages(context.TODO(), request.Filter)
res, err := InterruptableRPC(nil, func(ctx context.Context) ([]*pb.Image, error) {
return client.ListImages(ctx, request.Filter)
})
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -790,7 +811,9 @@ func ImageStatus(client internalapi.ImageManagerService, image string, verbose b
Verbose: verbose,
}
logrus.Debugf("ImageStatusRequest: %v", request)
res, err := client.ImageStatus(context.TODO(), request.Image, request.Verbose)
res, err := InterruptableRPC(nil, func(ctx context.Context) (*pb.ImageStatusResponse, error) {
return client.ImageStatus(ctx, request.Image, request.Verbose)
})
if err != nil {
return nil, err
}
Expand All @@ -806,16 +829,18 @@ func RemoveImage(client internalapi.ImageManagerService, image string) error {
}
request := &pb.RemoveImageRequest{Image: &pb.ImageSpec{Image: image}}
logrus.Debugf("RemoveImageRequest: %v", request)
if err := client.RemoveImage(context.TODO(), request.Image); err != nil {
return err
}
return nil
_, err := InterruptableRPC(nil, func(ctx context.Context) (*pb.RemoveImageResponse, error) {
return nil, client.RemoveImage(ctx, request.Image)
})
return err
}

// ImageFsInfo sends an ImageStatusRequest to the server, and parses
// the returned ImageFsInfoResponse.
func ImageFsInfo(client internalapi.ImageManagerService) (*pb.ImageFsInfoResponse, error) {
res, err := client.ImageFsInfo(context.TODO())
res, err := InterruptableRPC(nil, func(ctx context.Context) (*pb.ImageFsInfoResponse, error) {
return client.ImageFsInfo(ctx)
})
if err != nil {
return nil, err
}
Expand Down
33 changes: 33 additions & 0 deletions cmd/crictl/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,39 @@ func SetupInterruptSignalHandler() <-chan struct{} {
return signalIntStopCh
}

func InterruptableRPC[T any](
ctx context.Context,
rpcFunc func(context.Context) (T, error),
) (res T, err error) {
if ctx == nil {
ctx = context.Background()
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()

resCh := make(chan T, 1)
errCh := make(chan error, 1)

go func() {
res, err := rpcFunc(ctx)
if err != nil {
errCh <- err
return
}
resCh <- res
}()

select {
case <-SetupInterruptSignalHandler():
cancel()
return res, fmt.Errorf("interrupted: %w", ctx.Err())
case err := <-errCh:
return res, err
case res := <-resCh:
return res, nil
}
}

type listOptions struct {
// id of container or sandbox
id string
Expand Down
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ require (
sigs.k8s.io/yaml v1.4.0
)

// TODO: Remove when https://github.com/kubernetes/kubernetes/pull/125659 got merged
replace (
k8s.io/cri-api => github.com/saschagrunert/cri-api v0.0.0-20240618114741-963ea415e294
k8s.io/cri-client => github.com/saschagrunert/cri-client v0.0.0-20240612092602-9286eedb7451
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/saschagrunert/cri-api v0.0.0-20240618114741-963ea415e294 h1:L6wIf3yxURJUr6gup60pT2dreV8CwlbjCqLZ2Mb/CdQ=
github.com/saschagrunert/cri-api v0.0.0-20240618114741-963ea415e294/go.mod h1:8SzLKTnltnWXG9FMIL4SHWcAnnPGssi5viN/SMMMf4k=
github.com/saschagrunert/cri-client v0.0.0-20240612092602-9286eedb7451 h1:t0+I+fsq3/3KDukd3Ml1vq3pDHpTq5qzNtjCIzOa6R0=
github.com/saschagrunert/cri-client v0.0.0-20240612092602-9286eedb7451/go.mod h1:jKU9x1FP/k4ktv2mZOA37kJmLjoggWsbJOU9FsOV5RM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down Expand Up @@ -238,10 +242,6 @@ k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
k8s.io/component-base v0.30.2 h1:pqGBczYoW1sno8q9ObExUqrYSKhtE5rW3y6gX88GZII=
k8s.io/component-base v0.30.2/go.mod h1:yQLkQDrkK8J6NtP+MGJOws+/PPeEXNpwFixsUI7h/OE=
k8s.io/cri-api v0.31.0-alpha.0.0.20240528091733-69e407966029 h1:P+TWC7iOMWA2mWiNTLgeCr9z0TKwp22PMHkfF0woFQI=
k8s.io/cri-api v0.31.0-alpha.0.0.20240528091733-69e407966029/go.mod h1:bUzKm5FAhhVPHj344pvpKRIdGJMJ79mBHGrubR3TqZY=
k8s.io/cri-client v0.31.0-alpha.0.0.20240530211015-c9749ee02fc0 h1:A/qaNv8usB/HEZeWRcFe117POP0Sheqc9xnuYrBxYu8=
k8s.io/cri-client v0.31.0-alpha.0.0.20240530211015-c9749ee02fc0/go.mod h1:TarJVY/GTbu+Ht1IqT6eh5QXXxKwMfb2+7TpY/XlAhs=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
Expand Down
4 changes: 2 additions & 2 deletions pkg/framework/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,9 @@ func PullPublicImage(c internalapi.ImageManagerService, imageName string, podCon
imageSpec := &runtimeapi.ImageSpec{
Image: imageName,
}
id, err := c.PullImage(context.TODO(), imageSpec, nil, podConfig)
res, err := c.PullImage(context.TODO(), imageSpec, nil, podConfig)
ExpectNoError(err, "failed to pull image: %v", err)
return id
return res.GetImageRef()
}

// LoadYamlFile attempts to load the given YAML file into the given struct.
Expand Down
Loading

0 comments on commit d8fdb7a

Please sign in to comment.