commit
a5591d34b7
9 changed files with 257 additions and 1 deletions
|
@ -53,7 +53,9 @@ func getConfig(c *cli.Context) (*libkpod.Config, error) {
|
|||
if c.Bool("debug") {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
if c.GlobalIsSet("runtime") {
|
||||
config.Runtime = c.GlobalString("runtime")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ func main() {
|
|||
mountCommand,
|
||||
pullCommand,
|
||||
pushCommand,
|
||||
renameCommand,
|
||||
rmiCommand,
|
||||
saveCommand,
|
||||
tagCommand,
|
||||
|
@ -57,6 +58,10 @@ func main() {
|
|||
Name: "runroot",
|
||||
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{
|
||||
Name: "storage-driver, s",
|
||||
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
|
||||
}
|
|
@ -181,6 +181,26 @@ _kpod_push() {
|
|||
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() {
|
||||
local boolean_options="
|
||||
--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**
|
||||
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**
|
||||
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 an image from local storage to elsewhere
|
||||
|
||||
### rename
|
||||
Rename a container
|
||||
|
||||
### rmi
|
||||
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (c *Container) NetNsPath() (string, error) {
|
||||
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