Skip to content

Commit

Permalink
Implement kpod rm
Browse files Browse the repository at this point in the history
Kpod rm removes a container from the system

Signed-off-by: Ryan Cole <rcyoalne@gmail.com>

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Signed-off-by: umohnani8 <umohnani@redhat.com>
  • Loading branch information
rhatdan authored and umohnani8 committed Sep 5, 2017
1 parent 8538c40 commit c88bc13
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 60 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -55,6 +55,7 @@ It is currently in active development in the Kubernetes community through the [d
| [kpod-pull(1)](/docs/kpod-pull.1.md) | Pull an image from a registry |[![...](/docs/play.png)](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)|
| [kpod-push(1)](/docs/kpod-push.1.md) | Push an image to a specified destination |[![...](/docs/play.png)](https://asciinema.org/a/133276)|
| [kpod-rename(1)](/docs/kpod-rename.1.md) | Rename a container ||
| [kpod-rm(1)](/docs/kpod-rm.1.md) | Removes one or more containers ||
| [kpod-rmi(1)](/docs/kpod-rmi.1.md) | Removes one or more images |[![...](/docs/play.png)](https://asciinema.org/a/133799)|
| [kpod-save(1)](/docs/kpod-save.1.md) | Saves an image to an archive |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)|
| [kpod-stats(1)](/docs/kpod-stats.1.md) | Display a live stream of one or more containers' resource usage statistics||
Expand Down
1 change: 1 addition & 0 deletions cmd/kpod/main.go
Expand Up @@ -32,6 +32,7 @@ func main() {
pullCommand,
pushCommand,
renameCommand,
rmCommand,
rmiCommand,
saveCommand,
statsCommand,
Expand Down
65 changes: 65 additions & 0 deletions cmd/kpod/rm.go
@@ -0,0 +1,65 @@
package main

import (
"fmt"

"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/pkg/errors"
"github.com/urfave/cli"
)

var (
rmFlags = []cli.Flag{
cli.BoolFlag{
Name: "force, f",
Usage: "Force removal of a running container. The default is false",
},
}
rmDescription = "Remove one or more containers"
rmCommand = cli.Command{
Name: "rm",
Usage: fmt.Sprintf(`kpod rm will remove one or more containers from the host. The container name or ID can be used.
This does not remove images. Running containers will not be removed without the -f option.`),
Description: rmDescription,
Flags: rmFlags,
Action: rmCmd,
ArgsUsage: "",
}
)

// saveCmd saves the image to either docker-archive or oci
func rmCmd(c *cli.Context) error {
args := c.Args()
if len(args) == 0 {
return errors.Errorf("specify one or more containers to remove")
}

config, err := getConfig(c)
if err != nil {
return errors.Wrapf(err, "could not get config")
}
server, err := libkpod.New(config)
if err != nil {
return errors.Wrapf(err, "could not get container server")
}
defer server.Shutdown()
err = server.Update()
if err != nil {
return errors.Wrapf(err, "could not update list of containers")
}
force := c.Bool("force")

for _, container := range c.Args() {
id, err2 := server.Remove(container, force)
if err2 != nil {
if err == nil {
err = err2
} else {
err = errors.Wrapf(err, "%v. Stop the container before attempting removal or use -f\n", err2)
}
} else {
fmt.Println(id)
}
}
return err
}
22 changes: 22 additions & 0 deletions completions/bash/kpod
Expand Up @@ -255,6 +255,27 @@ _kpod_rename() {
esac
}

_kpod_rm() {
local boolean_options="
--force
-f
"

local options_with_args="
"

local all_options="$options_with_args $boolean_options"

case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
;;
*)
__kpod_list_containers
;;
esac
}

_kpod_rmi() {
local boolean_options="
--help
Expand Down Expand Up @@ -397,6 +418,7 @@ _kpod_kpod() {
pull
push
rename
rm
rmi
save
stats
Expand Down
31 changes: 31 additions & 0 deletions docs/kpod-rm.1.md
@@ -0,0 +1,31 @@
% kpod(1) kpod-rm - Remove one or more containers
% Ryan Cole
# kpod-rm "1" "August 2017" "kpod"

## NAME
kpod rm - Remove one or more containers

## SYNOPSIS
**kpod** **rm** [*options* [...]] container

## DESCRIPTION
Kpod rm will remove one or more containers from the host. The container name or ID can be used. This does not remove images. Running containers will not be removed without the -f option

## OPTIONS

**--force, f**

Force the removal of a running container


## EXAMPLE

kpod rm mywebserver

kpod rm -f 860a4b23

## SEE ALSO
kpod(1), kpod-rmi(1)

## HISTORY
August 2017, Originally compiled by Ryan Cole <rycole@redhat.com>
5 changes: 4 additions & 1 deletion docs/kpod.1.md
Expand Up @@ -36,7 +36,7 @@ has the capability to debug pods/images created by crio.
Path to the 'run directory' where all state information is stored

**--runtime**=**value**
Path to the OCI-compatible binary used to run containers
Path to the OCI compatible binary used to run containers

**--storage-driver, -s**=**value**
Select which storage driver is used to manage storage of images and containers (default is overlay)
Expand Down Expand Up @@ -88,6 +88,9 @@ Push an image from local storage to elsewhere
### rename
Rename a container

### rm
Remove one or more containers

### rmi
Removes one or more locally stored images

Expand Down
49 changes: 49 additions & 0 deletions libkpod/remove.go
@@ -0,0 +1,49 @@
package libkpod

import (
"os"
"path/filepath"

"github.com/kubernetes-incubator/cri-o/oci"
"github.com/pkg/errors"
)

// Remove removes a container
func (c *ContainerServer) Remove(container string, force bool) (string, error) {
ctr, err := c.LookupContainer(container)
if err != nil {
return "", err
}
ctrID := ctr.ID()

cState := c.runtime.ContainerStatus(ctr)
if cState.Status == oci.ContainerStateCreated || cState.Status == oci.ContainerStateRunning {
if force {
_, err = c.ContainerStop(container, -1)
if err != nil {
return "", errors.Wrapf(err, "unable to stop container %s", ctrID)
}
} else {
return "", errors.Errorf("cannot remove running container %s", ctrID)
}
}

if err := c.runtime.DeleteContainer(ctr); err != nil {
return "", errors.Wrapf(err, "failed to delete container %s", ctrID)
}
if err := os.Remove(filepath.Join(c.Config().RuntimeConfig.ContainerExitsDir, ctrID)); err != nil && !os.IsNotExist(err) {
return "", errors.Wrapf(err, "failed to remove container exit file %s", ctrID)
}
c.RemoveContainer(ctr)

if err := c.storageRuntimeServer.DeleteContainer(ctrID); err != nil {
return "", errors.Wrapf(err, "failed to delete storage for container %s", ctrID)
}

c.ReleaseContainerName(ctr.Name())

if err := c.ctrIDIndex.Delete(ctrID); err != nil {
return "", err
}
return ctrID, nil
}
28 changes: 28 additions & 0 deletions libkpod/stop.go
@@ -0,0 +1,28 @@
package libkpod

import (
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/pkg/errors"
)

// ContainerStop stops a running container with a grace period (i.e., timeout).
func (c *ContainerServer) ContainerStop(container string, timeout int64) (string, error) {
ctr, err := c.LookupContainer(container)
if err != nil {
return "", errors.Wrapf(err, "failed to find container %s", container)
}

cStatus := c.runtime.ContainerStatus(ctr)
if cStatus.Status != oci.ContainerStateStopped {
if err := c.runtime.StopContainer(ctr, timeout); err != nil {
return "", errors.Wrapf(err, "failed to stop container %s", ctr.ID())
}
if err := c.storageRuntimeServer.StopContainer(ctr.ID()); err != nil {
return "", errors.Wrapf(err, "failed to unmount container %s", ctr.ID())
}
}

c.ContainerStateToDisk(ctr)

return ctr.ID(), nil
}
38 changes: 1 addition & 37 deletions server/container_remove.go
@@ -1,11 +1,6 @@
package server

import (
"fmt"
"os"
"path/filepath"

"github.com/kubernetes-incubator/cri-o/oci"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
Expand All @@ -14,42 +9,11 @@ import (
// RemoveContainer removes the container. If the container is running, the container
// should be force removed.
func (s *Server) RemoveContainer(ctx context.Context, req *pb.RemoveContainerRequest) (*pb.RemoveContainerResponse, error) {
logrus.Debugf("RemoveContainerRequest %+v", req)
c, err := s.GetContainerFromRequest(req.ContainerId)
_, err := s.ContainerServer.Remove(req.ContainerId, true)
if err != nil {
return nil, err
}

cState := s.Runtime().ContainerStatus(c)
if cState.Status == oci.ContainerStateCreated || cState.Status == oci.ContainerStateRunning {
if err := s.Runtime().StopContainer(c, -1); err != nil {
return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err)
}
if err := s.StorageRuntimeServer().StopContainer(c.ID()); err != nil {
return nil, fmt.Errorf("failed to unmount container %s: %v", c.ID(), err)
}
}

if err := s.Runtime().DeleteContainer(c); err != nil {
return nil, fmt.Errorf("failed to delete container %s: %v", c.ID(), err)
}

if err := os.Remove(filepath.Join(s.config.ContainerExitsDir, c.ID())); err != nil && !os.IsNotExist(err) {
return nil, fmt.Errorf("failed to remove container exit file %s: %v", c.ID(), err)
}

s.removeContainer(c)

if err := s.StorageRuntimeServer().DeleteContainer(c.ID()); err != nil {
return nil, fmt.Errorf("failed to delete storage for container %s: %v", c.ID(), err)
}

s.ReleaseContainerName(c.Name())

if err := s.CtrIDIndex().Delete(c.ID()); err != nil {
return nil, err
}

resp := &pb.RemoveContainerResponse{}
logrus.Debugf("RemoveContainerResponse: %+v", resp)
return resp, nil
Expand Down
20 changes: 2 additions & 18 deletions server/container_stop.go
@@ -1,35 +1,19 @@
package server

import (
"fmt"

"github.com/kubernetes-incubator/cri-o/oci"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)

// StopContainer stops a running container with a grace period (i.e., timeout).
func (s *Server) StopContainer(ctx context.Context, req *pb.StopContainerRequest) (*pb.StopContainerResponse, error) {
logrus.Debugf("StopContainerRequest %+v", req)
c, err := s.GetContainerFromRequest(req.ContainerId)
_, err := s.ContainerServer.ContainerStop(req.ContainerId, req.Timeout)
if err != nil {
return nil, err
}

cStatus := s.Runtime().ContainerStatus(c)
if cStatus.Status != oci.ContainerStateStopped {
if err := s.Runtime().StopContainer(c, req.Timeout); err != nil {
return nil, fmt.Errorf("failed to stop container %s: %v", c.ID(), err)
}
if err := s.StorageRuntimeServer().StopContainer(c.ID()); err != nil {
return nil, fmt.Errorf("failed to unmount container %s: %v", c.ID(), err)
}
}

s.ContainerStateToDisk(c)

resp := &pb.StopContainerResponse{}
logrus.Debugf("StopContainerResponse %s: %+v", c.ID(), resp)
logrus.Debugf("StopContainerResponse %s: %+v", req.ContainerId, resp)
return resp, nil
}
7 changes: 5 additions & 2 deletions test/kpod_diff.bats
Expand Up @@ -5,16 +5,18 @@ load helpers
IMAGE="alpine:latest"
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT --storage-driver vfs"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT $STORAGE_OPTS"

function teardown() {
cleanup_test
}

@test "test diff of image and parent" {
run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} $KPOD_OPTIONS diff $IMAGE
echo "$output"
[ "$status" -eq 0 ]
echo "$output"
run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE
Expand All @@ -28,10 +30,11 @@ function teardown() {

@test "test diff with json output" {
run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE
echo "$output"
[ "$status" -eq 0 ]
# run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} diff --format json $IMAGE | python -m json.tool"
run ${KPOD_BINARY} $KPOD_OPTIONS diff --format json $IMAGE
[ "$status" -eq 0 ]
echo "$output"
[ "$status" -eq 0 ]
run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE
}
2 changes: 1 addition & 1 deletion test/kpod_load.bats
Expand Up @@ -5,7 +5,7 @@ load helpers
IMAGE="alpine:latest"
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT --storage-driver vfs"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT $STORAGE_OPTS"

function teardown() {
cleanup_test
Expand Down

0 comments on commit c88bc13

Please sign in to comment.