mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 22:46:12 +00:00
dockershim: add support for annotations
This commit is contained in:
parent
5e318cd749
commit
2f60b72dd3
@ -55,14 +55,15 @@ func toRuntimeAPIContainer(c *dockertypes.Container) (*runtimeApi.Container, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labels, annotations := extractLabels(c.Labels)
|
||||
return &runtimeApi.Container{
|
||||
Id: &c.ID,
|
||||
Metadata: metadata,
|
||||
Image: &runtimeApi.ImageSpec{Image: &c.Image},
|
||||
ImageRef: &c.ImageID,
|
||||
State: &state,
|
||||
// TODO: Extract annotations from labels.
|
||||
Labels: c.Labels,
|
||||
Id: &c.ID,
|
||||
Metadata: metadata,
|
||||
Image: &runtimeApi.ImageSpec{Image: &c.Image},
|
||||
ImageRef: &c.ImageID,
|
||||
State: &state,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -113,11 +114,13 @@ func toRuntimeAPISandbox(c *dockertypes.Container) (*runtimeApi.PodSandbox, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labels, annotations := extractLabels(c.Labels)
|
||||
return &runtimeApi.PodSandbox{
|
||||
Id: &c.ID,
|
||||
Metadata: metadata,
|
||||
State: &state,
|
||||
CreatedAt: &c.Created,
|
||||
Labels: c.Labels, // TODO: Need to disthinguish annotaions and labels.
|
||||
Id: &c.ID,
|
||||
Metadata: metadata,
|
||||
State: &state,
|
||||
CreatedAt: &c.Created,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}, nil
|
||||
}
|
||||
|
@ -88,9 +88,6 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
|
||||
return "", fmt.Errorf("sandbox config is nil for container %q", config.Metadata.GetName())
|
||||
}
|
||||
|
||||
// Merge annotations and labels because docker supports only labels.
|
||||
// TODO: add a prefix to annotations so that we can distinguish labels and
|
||||
// annotations when reading back them from the docker container.
|
||||
labels := makeLabels(config.GetLabels(), config.GetAnnotations())
|
||||
// Apply a the container type label.
|
||||
labels[containerTypeLabelKey] = containerTypeLabelContainer
|
||||
@ -284,21 +281,21 @@ func (ds *dockerService) ContainerStatus(containerID string) (*runtimeApi.Contai
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels, annotations := extractLabels(r.Config.Labels)
|
||||
return &runtimeApi.ContainerStatus{
|
||||
Id: &r.ID,
|
||||
Metadata: metadata,
|
||||
Image: &runtimeApi.ImageSpec{Image: &r.Config.Image},
|
||||
ImageRef: &r.Image,
|
||||
Mounts: mounts,
|
||||
ExitCode: &exitCode,
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
StartedAt: &st,
|
||||
FinishedAt: &ft,
|
||||
Reason: &reason,
|
||||
// TODO: We write annotations as labels on the docker containers. All
|
||||
// these annotations will be read back as labels. Need to fix this.
|
||||
Labels: r.Config.Labels,
|
||||
Id: &r.ID,
|
||||
Metadata: metadata,
|
||||
Image: &runtimeApi.ImageSpec{Image: &r.Config.Image},
|
||||
ImageRef: &r.Image,
|
||||
Mounts: mounts,
|
||||
ExitCode: &exitCode,
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
StartedAt: &st,
|
||||
FinishedAt: &ft,
|
||||
Reason: &reason,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,15 @@ import (
|
||||
)
|
||||
|
||||
// A helper to create a basic config.
|
||||
func makeContainerConfig(sConfig *runtimeApi.PodSandboxConfig, name, image string, attempt uint32) *runtimeApi.ContainerConfig {
|
||||
func makeContainerConfig(sConfig *runtimeApi.PodSandboxConfig, name, image string, attempt uint32, labels, annotations map[string]string) *runtimeApi.ContainerConfig {
|
||||
return &runtimeApi.ContainerConfig{
|
||||
Metadata: &runtimeApi.ContainerMetadata{
|
||||
Name: &name,
|
||||
Attempt: &attempt,
|
||||
},
|
||||
Image: &runtimeApi.ImageSpec{Image: &image},
|
||||
Image: &runtimeApi.ImageSpec{Image: &image},
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,8 +51,10 @@ func TestListContainers(t *testing.T) {
|
||||
for i := 0; i < 3; i++ {
|
||||
s := makeSandboxConfig(fmt.Sprintf("%s%d", podName, i),
|
||||
fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0)
|
||||
labels := map[string]string{"abc.xyz": fmt.Sprintf("label%d", i)}
|
||||
annotations := map[string]string{"foo.bar.baz": fmt.Sprintf("annotaion%d", i)}
|
||||
c := makeContainerConfig(s, fmt.Sprintf("%s%d", containerName, i),
|
||||
fmt.Sprintf("%s:v%d", image, i), uint32(i))
|
||||
fmt.Sprintf("%s:v%d", image, i), uint32(i), labels, annotations)
|
||||
sConfigs = append(sConfigs, s)
|
||||
configs = append(configs, c)
|
||||
}
|
||||
@ -69,12 +73,13 @@ func TestListContainers(t *testing.T) {
|
||||
// Prepend to the expected list because ListContainers returns
|
||||
// the most recent containers first.
|
||||
expected = append([]*runtimeApi.Container{{
|
||||
Metadata: configs[i].Metadata,
|
||||
Id: &id,
|
||||
State: &state,
|
||||
Image: configs[i].Image,
|
||||
ImageRef: &imageRef,
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelContainer},
|
||||
Metadata: configs[i].Metadata,
|
||||
Id: &id,
|
||||
State: &state,
|
||||
Image: configs[i].Image,
|
||||
ImageRef: &imageRef,
|
||||
Labels: configs[i].Labels,
|
||||
Annotations: configs[i].Annotations,
|
||||
}}, expected...)
|
||||
}
|
||||
containers, err := ds.ListContainers(nil)
|
||||
@ -88,7 +93,9 @@ func TestListContainers(t *testing.T) {
|
||||
func TestContainerStatus(t *testing.T) {
|
||||
ds, _, fClock := newTestDockerSevice()
|
||||
sConfig := makeSandboxConfig("foo", "bar", "1", 0)
|
||||
config := makeContainerConfig(sConfig, "pause", "iamimage", 0)
|
||||
labels := map[string]string{"abc.xyz": "foo"}
|
||||
annotations := map[string]string{"foo.bar.baz": "abc"}
|
||||
config := makeContainerConfig(sConfig, "pause", "iamimage", 0, labels, annotations)
|
||||
|
||||
var defaultTime time.Time
|
||||
dt := defaultTime.Unix()
|
||||
@ -100,17 +107,18 @@ func TestContainerStatus(t *testing.T) {
|
||||
reason := ""
|
||||
|
||||
expected := &runtimeApi.ContainerStatus{
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
StartedAt: &st,
|
||||
FinishedAt: &ft,
|
||||
Metadata: config.Metadata,
|
||||
Image: config.Image,
|
||||
ImageRef: &imageRef,
|
||||
ExitCode: &exitCode,
|
||||
Reason: &reason,
|
||||
Mounts: []*runtimeApi.Mount{},
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelContainer},
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
StartedAt: &st,
|
||||
FinishedAt: &ft,
|
||||
Metadata: config.Metadata,
|
||||
Image: config.Image,
|
||||
ImageRef: &imageRef,
|
||||
ExitCode: &exitCode,
|
||||
Reason: &reason,
|
||||
Mounts: []*runtimeApi.Mount{},
|
||||
Labels: config.Labels,
|
||||
Annotations: config.Annotations,
|
||||
}
|
||||
|
||||
// Create the container.
|
||||
|
@ -123,17 +123,16 @@ func (ds *dockerService) PodSandboxStatus(podSandboxID string) (*runtimeApi.PodS
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels, annotations := extractLabels(r.Config.Labels)
|
||||
return &runtimeApi.PodSandboxStatus{
|
||||
Id: &r.ID,
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
Metadata: metadata,
|
||||
// TODO: We write annotations as labels on the docker containers. All
|
||||
// these annotations will be read back as labels. Need to fix this.
|
||||
// Also filter out labels only relevant to this shim.
|
||||
Labels: r.Config.Labels,
|
||||
Network: network,
|
||||
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &netNS}},
|
||||
Id: &r.ID,
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
Metadata: metadata,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
Network: network,
|
||||
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &netNS}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,10 @@ import (
|
||||
|
||||
// A helper to create a basic config.
|
||||
func makeSandboxConfig(name, namespace, uid string, attempt uint32) *runtimeApi.PodSandboxConfig {
|
||||
return makeSandboxConfigWithLabelsAndAnnotations(name, namespace, uid, attempt, map[string]string{}, map[string]string{})
|
||||
}
|
||||
|
||||
func makeSandboxConfigWithLabelsAndAnnotations(name, namespace, uid string, attempt uint32, labels, annotations map[string]string) *runtimeApi.PodSandboxConfig {
|
||||
return &runtimeApi.PodSandboxConfig{
|
||||
Metadata: &runtimeApi.PodSandboxMetadata{
|
||||
Name: &name,
|
||||
@ -36,6 +40,8 @@ func makeSandboxConfig(name, namespace, uid string, attempt uint32) *runtimeApi.
|
||||
Uid: &uid,
|
||||
Attempt: &attempt,
|
||||
},
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,8 +52,11 @@ func TestListSandboxes(t *testing.T) {
|
||||
name, namespace := "foo", "bar"
|
||||
configs := []*runtimeApi.PodSandboxConfig{}
|
||||
for i := 0; i < 3; i++ {
|
||||
c := makeSandboxConfig(fmt.Sprintf("%s%d", name, i),
|
||||
fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0)
|
||||
c := makeSandboxConfigWithLabelsAndAnnotations(fmt.Sprintf("%s%d", name, i),
|
||||
fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0,
|
||||
map[string]string{"label": fmt.Sprintf("foo%d", i)},
|
||||
map[string]string{"annotation": fmt.Sprintf("bar%d", i)},
|
||||
)
|
||||
configs = append(configs, c)
|
||||
}
|
||||
|
||||
@ -60,11 +69,12 @@ func TestListSandboxes(t *testing.T) {
|
||||
// Prepend to the expected list because ListPodSandbox returns
|
||||
// the most recent sandbox first.
|
||||
expected = append([]*runtimeApi.PodSandbox{{
|
||||
Metadata: configs[i].Metadata,
|
||||
Id: &id,
|
||||
State: &state,
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelSandbox},
|
||||
CreatedAt: &createdAt,
|
||||
Metadata: configs[i].Metadata,
|
||||
Id: &id,
|
||||
State: &state,
|
||||
CreatedAt: &createdAt,
|
||||
Labels: configs[i].Labels,
|
||||
Annotations: configs[i].Annotations,
|
||||
}}, expected...)
|
||||
}
|
||||
sandboxes, err := ds.ListPodSandbox(nil)
|
||||
@ -77,7 +87,9 @@ func TestListSandboxes(t *testing.T) {
|
||||
// the status returned reflects the operations performed.
|
||||
func TestSandboxStatus(t *testing.T) {
|
||||
ds, _, fClock := newTestDockerSevice()
|
||||
config := makeSandboxConfig("foo", "bar", "1", 0)
|
||||
labels := map[string]string{"label": "foobar1"}
|
||||
annotations := map[string]string{"annotation": "abc"}
|
||||
config := makeSandboxConfigWithLabelsAndAnnotations("foo", "bar", "1", 0, labels, annotations)
|
||||
|
||||
// TODO: The following variables depend on the internal
|
||||
// implementation of FakeDockerClient, and should be fixed.
|
||||
@ -87,12 +99,13 @@ func TestSandboxStatus(t *testing.T) {
|
||||
state := runtimeApi.PodSandBoxState_READY
|
||||
ct := int64(0)
|
||||
expected := &runtimeApi.PodSandboxStatus{
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
Metadata: config.Metadata,
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelSandbox},
|
||||
Network: &runtimeApi.PodSandboxNetworkStatus{Ip: &fakeIP},
|
||||
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &fakeNS}},
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
Metadata: config.Metadata,
|
||||
Network: &runtimeApi.PodSandboxNetworkStatus{Ip: &fakeIP},
|
||||
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &fakeNS}},
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
}
|
||||
|
||||
// Create the sandbox.
|
||||
|
@ -30,6 +30,10 @@ import (
|
||||
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationPrefix = "annotation."
|
||||
)
|
||||
|
||||
// apiVersion implements kubecontainer.Version interface by implementing
|
||||
// Compare() and String(). It uses the compare function of engine-api to
|
||||
// compare docker apiversions.
|
||||
@ -57,23 +61,43 @@ func generateEnvList(envs []*runtimeApi.KeyValue) (result []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Merge annotations and labels because docker supports only labels.
|
||||
// TODO: Need to be able to distinguish annotations from labels; otherwise, we
|
||||
// couldn't restore the information when reading the labels back from docker.
|
||||
// makeLabels converts annotations to labels and merge them with the given
|
||||
// labels. This is necessary because docker does not support annotations;
|
||||
// we *fake* annotations using labels. Note that docker labels are not
|
||||
// updatable.
|
||||
func makeLabels(labels, annotations map[string]string) map[string]string {
|
||||
merged := make(map[string]string)
|
||||
for k, v := range labels {
|
||||
merged[k] = v
|
||||
}
|
||||
for k, v := range annotations {
|
||||
if _, ok := merged[k]; !ok {
|
||||
// Don't overwrite the key if it already exists.
|
||||
merged[k] = v
|
||||
}
|
||||
// Assume there won't be conflict.
|
||||
merged[fmt.Sprintf("%s%s", annotationPrefix, k)] = v
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
// extractLabels converts raw docker labels to the CRI labels and annotations.
|
||||
// It also filters out internal labels used by this shim.
|
||||
func extractLabels(input map[string]string) (map[string]string, map[string]string) {
|
||||
labels := make(map[string]string)
|
||||
annotations := make(map[string]string)
|
||||
for k, v := range input {
|
||||
// Check if the key is used internally by the shim.
|
||||
// TODO: containerTypeLabelKey is the only internal label the shim uses
|
||||
// right now. Expand this to a list later.
|
||||
if k == containerTypeLabelKey {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(k, annotationPrefix) {
|
||||
annotations[strings.TrimPrefix(k, annotationPrefix)] = v
|
||||
continue
|
||||
}
|
||||
labels[k] = v
|
||||
}
|
||||
return labels, annotations
|
||||
}
|
||||
|
||||
// generateMountBindings converts the mount list to a list of strings that
|
||||
// can be understood by docker.
|
||||
// Each element in the string is in the form of:
|
||||
|
34
pkg/kubelet/dockershim/helpers_test.go
Normal file
34
pkg/kubelet/dockershim/helpers_test.go
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dockershim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLabelsAndAnnotationsRoundTrip(t *testing.T) {
|
||||
expectedLabels := map[string]string{"foo.123.abc": "baz", "bar.456.xyz": "qwe"}
|
||||
expectedAnnotations := map[string]string{"uio.ert": "dfs", "jkl": "asd"}
|
||||
// Merge labels and annotations into docker labels.
|
||||
dockerLabels := makeLabels(expectedLabels, expectedAnnotations)
|
||||
// Extract labels and annotations from docker labels.
|
||||
actualLabels, actualAnnotations := extractLabels(dockerLabels)
|
||||
assert.Equal(t, expectedLabels, actualLabels)
|
||||
assert.Equal(t, expectedAnnotations, actualAnnotations)
|
||||
}
|
Loading…
Reference in New Issue
Block a user