mirror of
https://github.com/containers/podman.git
synced 2025-06-09 00:53:41 +08:00
14
README.md
14
README.md
@ -71,20 +71,6 @@ A little configuration by an administrator is required before rootless Podman ca
|
|||||||
See [Skopeo](https://github.com/containers/skopeo/) for those tasks.
|
See [Skopeo](https://github.com/containers/skopeo/) for those tasks.
|
||||||
* Support for the Kubernetes CRI interface for container management.
|
* Support for the Kubernetes CRI interface for container management.
|
||||||
The [CRI-O](https://github.com/cri-o/cri-o) daemon specializes in that.
|
The [CRI-O](https://github.com/cri-o/cri-o) daemon specializes in that.
|
||||||
* Supporting `docker-compose`. We believe that Kubernetes is the defacto
|
|
||||||
standard for composing Pods and for orchestrating containers, making
|
|
||||||
Kubernetes YAML a defacto standard file format. Hence, Podman allows the
|
|
||||||
creation and execution of Pods from a Kubernetes YAML file (see
|
|
||||||
[podman-play-kube](https://github.com/containers/podman/blob/master/docs/source/markdown/podman-play-kube.1.md)).
|
|
||||||
Podman can also generate Kubernetes YAML based on a container or Pod (see
|
|
||||||
[podman-generate-kube](https://github.com/containers/podman/blob/master/docs/source/markdown/podman-generate-kube.1.md)),
|
|
||||||
which allows for an easy transition from a local development environment
|
|
||||||
to a production Kubernetes cluster. If Kubernetes does not fit your requirements,
|
|
||||||
there are other third-party tools that support the docker-compose format such as
|
|
||||||
[kompose](https://github.com/kubernetes/kompose/) and
|
|
||||||
[podman-compose](https://github.com/muayyad-alsadi/podman-compose)
|
|
||||||
that might be appropriate for your environment. This situation may change with
|
|
||||||
the addition of the REST API.
|
|
||||||
|
|
||||||
## OCI Projects Plans
|
## OCI Projects Plans
|
||||||
|
|
||||||
|
56
cmd/podman/containers/rename.go
Normal file
56
cmd/podman/containers/rename.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package containers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/podman/v2/cmd/podman/common"
|
||||||
|
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||||
|
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
renameDescription = "The podman rename command allows you to rename an existing container"
|
||||||
|
renameCommand = &cobra.Command{
|
||||||
|
Use: "rename CONTAINER NAME",
|
||||||
|
Short: "Rename an existing container",
|
||||||
|
Long: renameDescription,
|
||||||
|
RunE: rename,
|
||||||
|
Args: cobra.ExactArgs(2),
|
||||||
|
ValidArgsFunction: common.AutocompletePortCommand,
|
||||||
|
Example: "podman rename containerA newName",
|
||||||
|
}
|
||||||
|
|
||||||
|
containerRenameCommand = &cobra.Command{
|
||||||
|
Use: renameCommand.Use,
|
||||||
|
Short: renameCommand.Short,
|
||||||
|
Long: renameCommand.Long,
|
||||||
|
RunE: renameCommand.RunE,
|
||||||
|
Args: renameCommand.Args,
|
||||||
|
ValidArgsFunction: renameCommand.ValidArgsFunction,
|
||||||
|
Example: "podman container rename containerA newName",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// TODO: Once bindings are done, add this to TunnelMode
|
||||||
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
|
Mode: []entities.EngineMode{entities.ABIMode},
|
||||||
|
Command: renameCommand,
|
||||||
|
})
|
||||||
|
|
||||||
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
|
Mode: []entities.EngineMode{entities.ABIMode},
|
||||||
|
Command: containerRenameCommand,
|
||||||
|
Parent: containerCmd,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func rename(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) > 2 {
|
||||||
|
return errors.Errorf("must provide at least two arguments to rename")
|
||||||
|
}
|
||||||
|
renameOpts := entities.ContainerRenameOptions{
|
||||||
|
NewName: args[1],
|
||||||
|
}
|
||||||
|
return registry.ContainerEngine().ContainerRename(registry.GetContext(), args[0], renameOpts)
|
||||||
|
}
|
@ -75,6 +75,8 @@ Commands
|
|||||||
|
|
||||||
:doc:`push <markdown/podman-push.1>` Push an image to a specified destination
|
:doc:`push <markdown/podman-push.1>` Push an image to a specified destination
|
||||||
|
|
||||||
|
:doc:`rename <markdown/podman-rename.1>` Rename an existing container
|
||||||
|
|
||||||
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
|
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
|
||||||
|
|
||||||
:doc:`rm <markdown/podman-rm.1>` Remove one or more containers
|
:doc:`rm <markdown/podman-rm.1>` Remove one or more containers
|
||||||
|
@ -41,6 +41,8 @@ Manage Containers
|
|||||||
|
|
||||||
:doc:`ps <markdown/podman-ps.1>` List containers
|
:doc:`ps <markdown/podman-ps.1>` List containers
|
||||||
|
|
||||||
|
:doc:`rename <markdown/podman-rename.1>` Rename an existing container
|
||||||
|
|
||||||
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
|
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
|
||||||
|
|
||||||
:doc:`restore <markdown/podman-container-restore.1>` Restores one or more containers from a checkpoint
|
:doc:`restore <markdown/podman-container-restore.1>` Restores one or more containers from a checkpoint
|
||||||
|
@ -33,6 +33,7 @@ The container command allows you to manage containers
|
|||||||
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
|
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
|
||||||
| prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. |
|
| prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. |
|
||||||
| ps | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
|
| ps | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
|
||||||
|
| rename | [podman-rename(1)](podman-rename.1.md) | Rename an existing container. |
|
||||||
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
|
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
|
||||||
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
|
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
|
||||||
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
||||||
|
38
docs/source/markdown/podman-rename.1.md
Normal file
38
docs/source/markdown/podman-rename.1.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
% podman-rename(1)
|
||||||
|
|
||||||
|
## NAME
|
||||||
|
podman\-rename - Rename an existing container
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
**podman rename** *container* *newname*
|
||||||
|
|
||||||
|
**podman container rename** *container* *newname*
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
Rename changes the name of an existing container.
|
||||||
|
The old name will be freed, and will be available for use.
|
||||||
|
This command can be run on containers in any state.
|
||||||
|
However, running containers may not fully receive the effects until they are restarted - for example, a running container may still use the old name in its logs.
|
||||||
|
At present, only containers are supported; pods and volumes cannot be renamed.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
## EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
# Rename a container by name
|
||||||
|
$ podman rename oldContainer aNewName
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# Rename a container by ID
|
||||||
|
$ podman rename 717716c00a6b testcontainer
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# Use the container rename alias
|
||||||
|
$ podman container rename 6e7514b47180 databaseCtr
|
||||||
|
```
|
||||||
|
|
||||||
|
## SEE ALSO
|
||||||
|
podman(1), podman-create(1), podman-run(1)
|
@ -247,6 +247,7 @@ the exit codes follow the `chroot` standard, see below:
|
|||||||
| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
|
| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
|
||||||
| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
|
| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
|
||||||
| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
|
| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
|
||||||
|
| [podman-rename(1)](podman-rename.1.md) | Rename an existing container. |
|
||||||
| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
|
| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
|
||||||
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
||||||
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
|
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
|
||||||
|
@ -72,6 +72,140 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config
|
|||||||
return r.setupContainer(ctx, ctr)
|
return r.setupContainer(ctx, ctr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenameContainer renames the given container.
|
||||||
|
// The given container object will be rendered unusable, and a new, renamed
|
||||||
|
// Container will be returned.
|
||||||
|
func (r *Runtime) RenameContainer(ctx context.Context, ctr *Container, newName string) (*Container, error) {
|
||||||
|
ctr.lock.Lock()
|
||||||
|
defer ctr.lock.Unlock()
|
||||||
|
|
||||||
|
if err := ctr.syncContainer(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if newName == "" || !define.NameRegex.MatchString(newName) {
|
||||||
|
return nil, define.RegexError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the name is available.
|
||||||
|
// This is *100% NOT ATOMIC* so any failures in-flight will do
|
||||||
|
// *VERY BAD THINGS* to the state. So we have to try and catch all we
|
||||||
|
// can before starting.
|
||||||
|
if _, err := r.state.LookupContainerID(newName); err == nil {
|
||||||
|
return nil, errors.Wrapf(define.ErrCtrExists, "name %s is already in use by another container", newName)
|
||||||
|
}
|
||||||
|
if _, err := r.state.LookupPod(newName); err == nil {
|
||||||
|
return nil, errors.Wrapf(define.ErrPodExists, "name %s is already in use by another pod", newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Investigate if it is possible to remove this limitation.
|
||||||
|
depCtrs, err := r.state.ContainerInUse(ctr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(depCtrs) > 0 {
|
||||||
|
return nil, errors.Wrapf(define.ErrCtrExists, "cannot rename container %s as it is in use by other containers: %v", ctr.ID(), strings.Join(depCtrs, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to pull an updated config, in case another rename fired and
|
||||||
|
// the config was re-written.
|
||||||
|
newConf, err := r.state.GetContainerConfig(ctr.ID())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error retrieving container %s configuration from DB to remove", ctr.ID())
|
||||||
|
}
|
||||||
|
ctr.config = newConf
|
||||||
|
|
||||||
|
// TODO: This is going to fail if we have active exec sessions, too.
|
||||||
|
// Investigate fixing that at a later date.
|
||||||
|
|
||||||
|
var pod *Pod
|
||||||
|
if ctr.config.Pod != "" {
|
||||||
|
tmpPod, err := r.state.Pod(ctr.config.Pod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error retrieving container %s pod", ctr.ID())
|
||||||
|
}
|
||||||
|
pod = tmpPod
|
||||||
|
// Lock pod to ensure it's not removed while we're working
|
||||||
|
pod.lock.Lock()
|
||||||
|
defer pod.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock all volumes to ensure they are not removed while we're working
|
||||||
|
volsLocked := make(map[string]bool)
|
||||||
|
for _, namedVol := range ctr.config.NamedVolumes {
|
||||||
|
if volsLocked[namedVol.Name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vol, err := r.state.Volume(namedVol.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error retrieving volume used by container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
volsLocked[vol.Name()] = true
|
||||||
|
vol.lock.Lock()
|
||||||
|
defer vol.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("Going to rename container %s from %q to %q", ctr.ID(), ctr.Name(), newName)
|
||||||
|
|
||||||
|
// Step 1: remove the old container.
|
||||||
|
if pod != nil {
|
||||||
|
if err := r.state.RemoveContainerFromPod(pod, ctr); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error renaming container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := r.state.RemoveContainer(ctr); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error renaming container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Make a new container based on the old one.
|
||||||
|
// TODO: Should we deep-copy the container config and state, to be safe?
|
||||||
|
newCtr := new(Container)
|
||||||
|
newCtr.config = ctr.config
|
||||||
|
newCtr.state = ctr.state
|
||||||
|
newCtr.lock = ctr.lock
|
||||||
|
newCtr.ociRuntime = ctr.ociRuntime
|
||||||
|
newCtr.runtime = r
|
||||||
|
newCtr.rootlessSlirpSyncR = ctr.rootlessSlirpSyncR
|
||||||
|
newCtr.rootlessSlirpSyncW = ctr.rootlessSlirpSyncW
|
||||||
|
newCtr.rootlessPortSyncR = ctr.rootlessPortSyncR
|
||||||
|
newCtr.rootlessPortSyncW = ctr.rootlessPortSyncW
|
||||||
|
|
||||||
|
newCtr.valid = true
|
||||||
|
newCtr.config.Name = newName
|
||||||
|
|
||||||
|
// Step 3: Add that new container to the DB
|
||||||
|
if pod != nil {
|
||||||
|
if err := r.state.AddContainerToPod(pod, newCtr); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error renaming container %s", newCtr.ID())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := r.state.AddContainer(newCtr); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error renaming container %s", newCtr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Save the new container, to force the state to be written to
|
||||||
|
// the DB. This may not be necessary, depending on DB implementation,
|
||||||
|
// but let's do it to be safe.
|
||||||
|
if err := newCtr.save(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: rename the container in c/storage.
|
||||||
|
// This can fail if the name is already in use by a non-Podman
|
||||||
|
// container. This puts us in a bad spot - we've already renamed the
|
||||||
|
// container in Podman. We can swap the order, but then we have the
|
||||||
|
// opposite problem. Atomicity is a real problem here, with no easy
|
||||||
|
// solution.
|
||||||
|
if err := r.store.SetNames(newCtr.ID(), []string{newCtr.Name()}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newCtr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConfig) (*Container, error) {
|
func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConfig) (*Container, error) {
|
||||||
if rSpec == nil {
|
if rSpec == nil {
|
||||||
return nil, errors.Wrapf(define.ErrInvalidArg, "must provide a valid runtime spec to create container")
|
return nil, errors.Wrapf(define.ErrInvalidArg, "must provide a valid runtime spec to create container")
|
||||||
@ -393,7 +527,7 @@ func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool,
|
|||||||
// removePod is used only when removing pods. It instructs Podman to ignore
|
// removePod is used only when removing pods. It instructs Podman to ignore
|
||||||
// infra container protections, and *not* remove from the database (as pod
|
// infra container protections, and *not* remove from the database (as pod
|
||||||
// remove will handle that).
|
// remove will handle that).
|
||||||
func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, removeVolume bool, removePod bool) error {
|
func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, removeVolume, removePod bool) error {
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "removeContainer")
|
span, _ := opentracing.StartSpanFromContext(ctx, "removeContainer")
|
||||||
span.SetTag("type", "runtime")
|
span.SetTag("type", "runtime")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
@ -406,6 +540,18 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to refresh container config from the DB, to ensure that any
|
||||||
|
// changes (e.g. a rename) are picked up before we start removing.
|
||||||
|
// Since HasContainer above succeeded, we can safely assume the
|
||||||
|
// container exists.
|
||||||
|
// This is *very iffy* but it should be OK because the container won't
|
||||||
|
// exist once we're done.
|
||||||
|
newConf, err := r.state.GetContainerConfig(c.ID())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error retrieving container %s configuration from DB to remove", c.ID())
|
||||||
|
}
|
||||||
|
c.config = newConf
|
||||||
|
|
||||||
logrus.Debugf("Removing container %s", c.ID())
|
logrus.Debugf("Removing container %s", c.ID())
|
||||||
|
|
||||||
// We need to lock the pod before we lock the container.
|
// We need to lock the pod before we lock the container.
|
||||||
@ -413,7 +559,6 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
|
|||||||
// Don't need to do this in pod removal case - we're evicting the entire
|
// Don't need to do this in pod removal case - we're evicting the entire
|
||||||
// pod.
|
// pod.
|
||||||
var pod *Pod
|
var pod *Pod
|
||||||
var err error
|
|
||||||
runtime := c.runtime
|
runtime := c.runtime
|
||||||
if c.config.Pod != "" && !removePod {
|
if c.config.Pod != "" && !removePod {
|
||||||
pod, err = r.state.Pod(c.config.Pod)
|
pod, err = r.state.Pod(c.config.Pod)
|
||||||
|
@ -465,3 +465,34 @@ func formatCapabilities(slice []string) {
|
|||||||
slice[i] = strings.TrimPrefix(slice[i], "CAP_")
|
slice[i] = strings.TrimPrefix(slice[i], "CAP_")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RenameContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
|
|
||||||
|
name := utils.GetName(r)
|
||||||
|
query := struct {
|
||||||
|
Name string `schema:"name"`
|
||||||
|
}{}
|
||||||
|
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
|
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr, err := runtime.LookupContainer(name)
|
||||||
|
if err != nil {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := runtime.RenameContainer(r.Context(), ctr, query.Name); err != nil {
|
||||||
|
if errors.Cause(err) == define.ErrPodExists || errors.Cause(err) == define.ErrCtrExists {
|
||||||
|
utils.Error(w, "Something went wrong.", http.StatusConflict, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.WriteResponse(w, http.StatusNoContent, nil)
|
||||||
|
}
|
||||||
|
@ -291,9 +291,6 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
r.HandleFunc(VersionedPath("/containers/{name}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost)
|
r.HandleFunc(VersionedPath("/containers/{name}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost)
|
||||||
// Added non version path to URI to support docker non versioned paths
|
// Added non version path to URI to support docker non versioned paths
|
||||||
r.HandleFunc("/containers/{name}/pause", s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost)
|
r.HandleFunc("/containers/{name}/pause", s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost)
|
||||||
r.HandleFunc(VersionedPath("/containers/{name}/rename"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
|
|
||||||
// Added non version path to URI to support docker non versioned paths
|
|
||||||
r.HandleFunc("/containers/{name}/rename", s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
|
|
||||||
// swagger:operation POST /containers/{name}/restart compat restartContainer
|
// swagger:operation POST /containers/{name}/restart compat restartContainer
|
||||||
// ---
|
// ---
|
||||||
// tags:
|
// tags:
|
||||||
@ -610,6 +607,36 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// $ref: "#/responses/InternalError"
|
// $ref: "#/responses/InternalError"
|
||||||
r.HandleFunc(VersionedPath("/containers/{name}/export"), s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet)
|
r.HandleFunc(VersionedPath("/containers/{name}/export"), s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/containers/{name}/export", s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet)
|
r.HandleFunc("/containers/{name}/export", s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet)
|
||||||
|
// swagger:operation POST /containers/{name}/rename compat renameContainer
|
||||||
|
// ---
|
||||||
|
// tags:
|
||||||
|
// - containers (compat)
|
||||||
|
// summary: Rename an existing container
|
||||||
|
// description: Change the name of an existing container.
|
||||||
|
// parameters:
|
||||||
|
// - in: path
|
||||||
|
// name: name
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// description: Full or partial ID or full name of the container to rename
|
||||||
|
// - in: query
|
||||||
|
// name: name
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// description: New name for the container
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// responses:
|
||||||
|
// 204:
|
||||||
|
// description: no error
|
||||||
|
// 404:
|
||||||
|
// $ref: "#/responses/NoSuchContainer"
|
||||||
|
// 409:
|
||||||
|
// $ref: "#/responses/ConflictError"
|
||||||
|
// 500:
|
||||||
|
// $ref: "#/responses/InternalError"
|
||||||
|
r.HandleFunc(VersionedPath("/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/containers/{name}/rename", s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
libpod endpoints
|
libpod endpoints
|
||||||
@ -1463,5 +1490,34 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// 500:
|
// 500:
|
||||||
// $ref: "#/responses/InternalError"
|
// $ref: "#/responses/InternalError"
|
||||||
r.HandleFunc(VersionedPath("/libpod/containers/{name}/init"), s.APIHandler(libpod.InitContainer)).Methods(http.MethodPost)
|
r.HandleFunc(VersionedPath("/libpod/containers/{name}/init"), s.APIHandler(libpod.InitContainer)).Methods(http.MethodPost)
|
||||||
|
// swagger:operation POST /libpod/containers/{name}/rename libpod libpodRenameContainer
|
||||||
|
// ---
|
||||||
|
// tags:
|
||||||
|
// - containers
|
||||||
|
// summary: Rename an existing container
|
||||||
|
// description: Change the name of an existing container.
|
||||||
|
// parameters:
|
||||||
|
// - in: path
|
||||||
|
// name: name
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// description: Full or partial ID or full name of the container to rename
|
||||||
|
// - in: query
|
||||||
|
// name: name
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// description: New name for the container
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// responses:
|
||||||
|
// 204:
|
||||||
|
// description: no error
|
||||||
|
// 404:
|
||||||
|
// $ref: "#/responses/NoSuchContainer"
|
||||||
|
// 409:
|
||||||
|
// $ref: "#/responses/ConflictError"
|
||||||
|
// 500:
|
||||||
|
// $ref: "#/responses/InternalError"
|
||||||
|
r.HandleFunc(VersionedPath("/libpod/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -434,3 +434,9 @@ type ContainerStatsReport struct {
|
|||||||
// Results, set when there is no error.
|
// Results, set when there is no error.
|
||||||
Stats []define.ContainerStats
|
Stats []define.ContainerStats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainerRenameOptions describes input options for renaming a container.
|
||||||
|
type ContainerRenameOptions struct {
|
||||||
|
// NewName is the new name that will be given to the container.
|
||||||
|
NewName string
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ type ContainerEngine interface {
|
|||||||
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
|
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
|
||||||
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
|
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
|
||||||
ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
|
ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
|
||||||
|
ContainerRename(ctr context.Context, nameOrID string, options ContainerRenameOptions) error
|
||||||
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
||||||
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
|
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
|
||||||
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
||||||
|
@ -902,7 +902,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
|||||||
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
|
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
|
||||||
if errors.Cause(err) == define.ErrNoSuchCtr ||
|
if errors.Cause(err) == define.ErrNoSuchCtr ||
|
||||||
errors.Cause(err) == define.ErrCtrRemoved {
|
errors.Cause(err) == define.ErrCtrRemoved {
|
||||||
logrus.Warnf("Container %s does not exist: %v", ctr.ID(), err)
|
logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID())
|
||||||
} else {
|
} else {
|
||||||
logrus.Errorf("Error removing container %s: %v", ctr.ID(), err)
|
logrus.Errorf("Error removing container %s: %v", ctr.ID(), err)
|
||||||
}
|
}
|
||||||
@ -1312,3 +1312,17 @@ func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (
|
|||||||
|
|
||||||
return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
|
return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainerRename renames the given container.
|
||||||
|
func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error {
|
||||||
|
ctr, err := ic.Libpod.LookupContainer(nameOrID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := ic.Libpod.RenameContainer(ctx, ctr, opts.NewName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -820,3 +820,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
|
|||||||
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
|
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
|
||||||
return containers.ShouldRestart(ic.ClientCtx, id, nil)
|
return containers.ShouldRestart(ic.ClientCtx, id, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainerRename renames the given container.
|
||||||
|
func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error {
|
||||||
|
return errors.Errorf("NOT YET IMPLEMENTED")
|
||||||
|
}
|
||||||
|
93
test/e2e/rename_test.go
Normal file
93
test/e2e/rename_test.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/containers/podman/v2/test/utils"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("podman rename", func() {
|
||||||
|
var (
|
||||||
|
tempdir string
|
||||||
|
err error
|
||||||
|
podmanTest *PodmanTestIntegration
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
SkipIfRemote("Rename not yet implemented by podman-remote")
|
||||||
|
tempdir, err = CreateTempDirInTempDir()
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
podmanTest = PodmanTestCreate(tempdir)
|
||||||
|
podmanTest.Setup()
|
||||||
|
podmanTest.SeedImages()
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
podmanTest.Cleanup()
|
||||||
|
f := CurrentGinkgoTestDescription()
|
||||||
|
processTestResult(f)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman rename on non-existent container", func() {
|
||||||
|
session := podmanTest.Podman([]string{"rename", "doesNotExist", "aNewName"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Podman rename on existing container with bad name", func() {
|
||||||
|
ctrName := "testCtr"
|
||||||
|
ctr := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "top"})
|
||||||
|
ctr.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctr.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
newName := "invalid<>:char"
|
||||||
|
rename := podmanTest.Podman([]string{"rename", ctrName, newName})
|
||||||
|
rename.WaitWithDefaultTimeout()
|
||||||
|
Expect(rename.ExitCode()).To(Not(Equal(0)))
|
||||||
|
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", ctrName), "--format", "{{ .Names }}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps.ExitCode()).To(Equal(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring(ctrName))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Successfully rename a created container", func() {
|
||||||
|
ctrName := "testCtr"
|
||||||
|
ctr := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "top"})
|
||||||
|
ctr.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctr.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
newName := "aNewName"
|
||||||
|
rename := podmanTest.Podman([]string{"rename", ctrName, newName})
|
||||||
|
rename.WaitWithDefaultTimeout()
|
||||||
|
Expect(rename.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", newName), "--format", "{{ .Names }}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps.ExitCode()).To(Equal(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring(newName))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Successfully rename a running container", func() {
|
||||||
|
ctrName := "testCtr"
|
||||||
|
ctr := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, ALPINE, "top"})
|
||||||
|
ctr.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctr.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
newName := "aNewName"
|
||||||
|
rename := podmanTest.Podman([]string{"rename", ctrName, newName})
|
||||||
|
rename.WaitWithDefaultTimeout()
|
||||||
|
Expect(rename.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", newName), "--format", "{{ .Names }}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps.ExitCode()).To(Equal(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring(newName))
|
||||||
|
})
|
||||||
|
})
|
Reference in New Issue
Block a user