implement kpod rename
rename a container Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
This commit is contained in:
parent
a69631c1bd
commit
1eb21f8e15
9 changed files with 261 additions and 1 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
45
cmd/kpod/rename.go
Normal 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
|
||||||
|
}
|
|
@ -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
24
docs/kpod-rename.1.md
Normal 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>
|
|
@ -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
114
libkpod/rename.go
Normal 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]
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
35
test/kpod_rename.bats
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue