implement kpod rename

rename a container

Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
This commit is contained in:
Ryan Cole 2017-08-14 13:30:24 -04:00
parent a69631c1bd
commit 1eb21f8e15
9 changed files with 261 additions and 1 deletions

View file

@ -50,6 +50,8 @@ func getConfig(c *cli.Context) (*libkpod.Config, error) {
if c.Bool("debug") { if c.Bool("debug") {
logrus.SetLevel(logrus.DebugLevel) logrus.SetLevel(logrus.DebugLevel)
} }
if c.GlobalIsSet("runtime") {
config.Runtime = c.GlobalString("runtime")
}
return config, nil return config, nil
} }

View file

@ -33,6 +33,7 @@ func main() {
mountCommand, mountCommand,
pullCommand, pullCommand,
pushCommand, pushCommand,
renameCommand,
rmiCommand, rmiCommand,
saveCommand, saveCommand,
tagCommand, tagCommand,
@ -56,6 +57,10 @@ func main() {
Name: "runroot", Name: "runroot",
Usage: "path to the 'run directory' where all state information is stored", Usage: "path to the 'run directory' where all state information is stored",
}, },
cli.StringFlag{
Name: "runtime",
Usage: "path to the OCI-compatible binary used to run containers, default is /usr/bin/runc",
},
cli.StringFlag{ cli.StringFlag{
Name: "storage-driver, s", Name: "storage-driver, s",
Usage: "select which storage driver is used to manage storage of images and containers (default is overlay2)", Usage: "select which storage driver is used to manage storage of images and containers (default is overlay2)",

45
cmd/kpod/rename.go Normal file
View file

@ -0,0 +1,45 @@
package main
import (
"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var (
renameDescription = "Rename a container. Container may be created, running, paused, or stopped"
renameFlags = []cli.Flag{}
renameCommand = cli.Command{
Name: "rename",
Usage: "rename a container",
Description: renameDescription,
Action: renameCmd,
ArgsUsage: "CONTAINER NEW-NAME",
Flags: renameFlags,
}
)
func renameCmd(c *cli.Context) error {
if len(c.Args()) != 2 {
return errors.Errorf("Rename requires a src container name/ID and a dest container name")
}
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")
}
err = server.Update()
if err != nil {
return errors.Wrapf(err, "could not update list of containers")
}
err = server.ContainerRename(c.Args().Get(0), c.Args().Get(1))
if err != nil {
return errors.Wrapf(err, "could not rename container")
}
return nil
}

View file

@ -6,6 +6,10 @@ __kpod_list_images() {
COMPREPLY=($(compgen -W "$(kpod images -q)" -- $cur)) COMPREPLY=($(compgen -W "$(kpod images -q)" -- $cur))
} }
__kpod_list_containers() {
COMPREPLY=($(compgen -W "$(kpod ps -aq)" -- $cur))
}
_kpod_history() { _kpod_history() {
local options_with_args=" local options_with_args="
--format --format
@ -156,6 +160,26 @@ _kpod_push() {
esac esac
} }
_kpod_rename() {
local boolean_options="
--help
-h
"
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() { _kpod_rmi() {
local boolean_options=" local boolean_options="
--help --help

24
docs/kpod-rename.1.md Normal file
View file

@ -0,0 +1,24 @@
% kpod(1) kpod-rename - Rename a container
% Ryan Cole
# kpod-images "1" "March 2017" "kpod"
## NAME
kpod rename - Rename a container
## SYNOPSIS
**kpod** **rename** CONTAINER NEW-NAME
## DESCRIPTION
Rename a container. Container may be created, running, paused, or stopped
## EXAMPLE
kpod rename redis-container webserver
kpod rename a236b9a4 mycontainer
## SEE ALSO
kpod(1)
## HISTORY
March 2017, Originally compiled by Ryan Cole <rycole@redhat.com>

View file

@ -35,6 +35,9 @@ has the capability to debug pods/images created by crio.
**--runroot**=**value** **--runroot**=**value**
Path to the 'run directory' where all state information is stored Path to the 'run directory' where all state information is stored
**--runtime**=**value**
Path to the OCI-compatible binary used to run containers
**--storage-driver, -s**=**value** **--storage-driver, -s**=**value**
Select which storage driver is used to manage storage of images and containers (default is overlay) Select which storage driver is used to manage storage of images and containers (default is overlay)
@ -76,6 +79,9 @@ Pull an image from a registry
### push ### push
Push an image from local storage to elsewhere Push an image from local storage to elsewhere
### rename
Rename a container
### rmi ### rmi
Removes one or more locally stored images Removes one or more locally stored images

114
libkpod/rename.go Normal file
View file

@ -0,0 +1,114 @@
package libkpod
import (
"encoding/json"
"path/filepath"
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"github.com/docker/docker/pkg/ioutils"
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/kubernetes-incubator/cri-o/pkg/annotations"
"github.com/opencontainers/runtime-tools/generate"
)
const configFile = "config.json"
// ContainerRename renames the given container
func (c *ContainerServer) ContainerRename(container, name string) error {
ctr, err := c.LookupContainer(container)
if err != nil {
return err
}
oldName := ctr.Name()
_, err = c.ReserveContainerName(ctr.ID(), name)
if err != nil {
return err
}
defer func() {
if err != nil {
c.ReleaseContainerName(name)
} else {
c.ReleaseContainerName(oldName)
}
}()
// Update state.json
if err = c.updateStateName(ctr, name); err != nil {
return err
}
// Update config.json
configRuntimePath := filepath.Join(ctr.BundlePath(), configFile)
if err = updateConfigName(configRuntimePath, name); err != nil {
return err
}
configStoragePath := filepath.Join(ctr.Dir(), configFile)
if err = updateConfigName(configStoragePath, name); err != nil {
return err
}
// Update containers.json
if err = c.store.SetNames(ctr.ID(), []string{name}); err != nil {
return err
}
return nil
}
func updateConfigName(configPath, name string) error {
specgen, err := generate.NewFromFile(configPath)
if err != nil {
return err
}
specgen.AddAnnotation(annotations.Name, name)
specgen.AddAnnotation(annotations.Metadata, updateMetadata(specgen.Spec().Annotations, name))
return specgen.SaveToFile(configPath, generate.ExportOptions{})
}
func (c *ContainerServer) updateStateName(ctr *oci.Container, name string) error {
ctr.State().Annotations[annotations.Name] = name
ctr.State().Annotations[annotations.Metadata] = updateMetadata(ctr.State().Annotations, name)
// This is taken directly from c.ContainerStateToDisk(), which can't be used because of the call to UpdateStatus() in the first line
jsonSource, err := ioutils.NewAtomicFileWriter(ctr.StatePath(), 0644)
if err != nil {
return err
}
defer jsonSource.Close()
enc := json.NewEncoder(jsonSource)
return enc.Encode(c.runtime.ContainerStatus(ctr))
}
// Attempts to update a metadata annotation
func updateMetadata(specAnnotations map[string]string, name string) string {
oldMetadata := specAnnotations[annotations.Metadata]
containerType := specAnnotations[annotations.ContainerType]
if containerType == "container" {
metadata := runtime.ContainerMetadata{}
err := json.Unmarshal([]byte(oldMetadata), metadata)
if err != nil {
return oldMetadata
}
metadata.Name = name
m, err := json.Marshal(metadata)
if err != nil {
return oldMetadata
}
return string(m)
} else if containerType == "sandbox" {
metadata := runtime.PodSandboxMetadata{}
err := json.Unmarshal([]byte(oldMetadata), metadata)
if err != nil {
return oldMetadata
}
metadata.Name = name
m, err := json.Marshal(metadata)
if err != nil {
return oldMetadata
}
return string(m)
} else {
return specAnnotations[annotations.Metadata]
}
}

View file

@ -160,6 +160,11 @@ func (c *Container) Sandbox() string {
return c.sandbox return c.sandbox
} }
// Dir returns the the dir of the container
func (c *Container) Dir() string {
return c.dir
}
// NetNsPath returns the path to the network namespace of the container. // NetNsPath returns the path to the network namespace of the container.
func (c *Container) NetNsPath() (string, error) { func (c *Container) NetNsPath() (string, error) {
if c.state == nil { if c.state == nil {

35
test/kpod_rename.bats Normal file
View file

@ -0,0 +1,35 @@
#!/usr/bin/env bats
load helpers
IMAGE="redis:alpine"
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT $STORAGE_OPTS"
NEW_NAME="rename-test"
function teardown() {
cleanup_test
}
@test "kpod rename successful" {
start_crio
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
[ "$status" -eq 0 ]
run crioctl pod run --config "$TESTDATA"/sandbox_config.json
echo "$output"
pod_id="$output"
[ "$status" -eq 0 ]
run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id"
ctr_id="$output"
run ${KPOD_BINARY} $KPOD_OPTIONS rename "$ctr_id" "$NEW_NAME"
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} $KPOD_OPTIONS inspect "$ctr_id" --format {{.Name}}
echo "$output"
[ "$status" -eq 0 ]
[ "$output" == "$NEW_NAME" ]
cleanup_ctrs
cleanup_pods
stop_crio
}