aboutsummaryrefslogtreecommitdiff
path: root/libkpod/rename.go
blob: 7c0279bfe9cd0a9c0f527fb6bbaa10a1173a5c1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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]
	}
}