diff options
Diffstat (limited to 'libkpod/rename.go')
-rw-r--r-- | libkpod/rename.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/libkpod/rename.go b/libkpod/rename.go new file mode 100644 index 000000000..7c0279bfe --- /dev/null +++ b/libkpod/rename.go @@ -0,0 +1,114 @@ +package libkpod + +import ( + "encoding/json" + "path/filepath" + + "k8s.io/kubernetes/pkg/kubelet/apis/cri/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] + } +} |