Labels are consistently validated across services
* The combined size of a key/value pair cannot exceed 4096 bytes Signed-off-by: Jess Valarezo <valarezo.jessica@gmail.com>
This commit is contained in:
parent
d700a9c35b
commit
18c4322bb3
@ -65,6 +65,8 @@ type Container struct {
|
|||||||
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
// Labels provides an area to include arbitrary data on containers.
|
// Labels provides an area to include arbitrary data on containers.
|
||||||
//
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
|
//
|
||||||
// Note that to add a new value to this field, read the existing set and
|
// Note that to add a new value to this field, read the existing set and
|
||||||
// include the entire result in the update call.
|
// include the entire result in the update call.
|
||||||
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
|
@ -42,6 +42,8 @@ message Container {
|
|||||||
|
|
||||||
// Labels provides an area to include arbitrary data on containers.
|
// Labels provides an area to include arbitrary data on containers.
|
||||||
//
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
|
//
|
||||||
// Note that to add a new value to this field, read the existing set and
|
// Note that to add a new value to this field, read the existing set and
|
||||||
// include the entire result in the update call.
|
// include the entire result in the update call.
|
||||||
map<string, string> labels = 2;
|
map<string, string> labels = 2;
|
||||||
|
@ -115,7 +115,9 @@ type Info struct {
|
|||||||
CreatedAt time.Time `protobuf:"bytes,3,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
|
CreatedAt time.Time `protobuf:"bytes,3,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
|
||||||
// UpdatedAt provides the time the info was last updated.
|
// UpdatedAt provides the time the info was last updated.
|
||||||
UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||||
// Labels are arbitrary data on content.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +323,9 @@ type WriteContentRequest struct {
|
|||||||
// If this is empty and the message is not a commit, a response will be
|
// If this is empty and the message is not a commit, a response will be
|
||||||
// returned with the current write state.
|
// returned with the current write state.
|
||||||
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
|
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
// Labels are arbitrary data to set on commit.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,7,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,7,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,9 @@ message Info {
|
|||||||
// UpdatedAt provides the time the info was last updated.
|
// UpdatedAt provides the time the info was last updated.
|
||||||
google.protobuf.Timestamp updated_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
google.protobuf.Timestamp updated_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||||
|
|
||||||
// Labels are arbitrary data on content.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 5;
|
map<string, string> labels = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +272,9 @@ message WriteContentRequest {
|
|||||||
// returned with the current write state.
|
// returned with the current write state.
|
||||||
bytes data = 6;
|
bytes data = 6;
|
||||||
|
|
||||||
// Labels are arbitrary data to set on commit.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 7;
|
map<string, string> labels = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ type Image struct {
|
|||||||
// and do not get inherited into the package image in any way.
|
// and do not get inherited into the package image in any way.
|
||||||
//
|
//
|
||||||
// Labels may be updated using the field mask.
|
// Labels may be updated using the field mask.
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
// Target describes the content entry point of the image.
|
// Target describes the content entry point of the image.
|
||||||
Target containerd_types.Descriptor `protobuf:"bytes,3,opt,name=target" json:"target"`
|
Target containerd_types.Descriptor `protobuf:"bytes,3,opt,name=target" json:"target"`
|
||||||
|
@ -51,6 +51,7 @@ message Image {
|
|||||||
// and do not get inherited into the package image in any way.
|
// and do not get inherited into the package image in any way.
|
||||||
//
|
//
|
||||||
// Labels may be updated using the field mask.
|
// Labels may be updated using the field mask.
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 2;
|
map<string, string> labels = 2;
|
||||||
|
|
||||||
// Target describes the content entry point of the image.
|
// Target describes the content entry point of the image.
|
||||||
|
@ -55,6 +55,8 @@ type Namespace struct {
|
|||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
// Labels provides an area to include arbitrary data on namespaces.
|
// Labels provides an area to include arbitrary data on namespaces.
|
||||||
//
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
|
//
|
||||||
// Note that to add a new value to this field, read the existing set and
|
// Note that to add a new value to this field, read the existing set and
|
||||||
// include the entire result in the update call.
|
// include the entire result in the update call.
|
||||||
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
|
@ -32,6 +32,8 @@ message Namespace {
|
|||||||
|
|
||||||
// Labels provides an area to include arbitrary data on namespaces.
|
// Labels provides an area to include arbitrary data on namespaces.
|
||||||
//
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
|
//
|
||||||
// Note that to add a new value to this field, read the existing set and
|
// Note that to add a new value to this field, read the existing set and
|
||||||
// include the entire result in the update call.
|
// include the entire result in the update call.
|
||||||
map<string, string> labels = 2;
|
map<string, string> labels = 2;
|
||||||
|
@ -97,6 +97,8 @@ type PrepareSnapshotRequest struct {
|
|||||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"`
|
Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"`
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +119,8 @@ type ViewSnapshotRequest struct {
|
|||||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"`
|
Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"`
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +167,8 @@ type CommitSnapshotRequest struct {
|
|||||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
|
Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +194,8 @@ type Info struct {
|
|||||||
// UpdatedAt provides the time the info was last updated.
|
// UpdatedAt provides the time the info was last updated.
|
||||||
UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
Labels map[string]string `protobuf:"bytes,6,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,6,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ message PrepareSnapshotRequest {
|
|||||||
string parent = 3;
|
string parent = 3;
|
||||||
|
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 4;
|
map<string, string> labels = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +44,8 @@ message ViewSnapshotRequest {
|
|||||||
string parent = 3;
|
string parent = 3;
|
||||||
|
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 4;
|
map<string, string> labels = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +73,8 @@ message CommitSnapshotRequest {
|
|||||||
string key = 3;
|
string key = 3;
|
||||||
|
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 4;
|
map<string, string> labels = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +105,8 @@ message Info {
|
|||||||
google.protobuf.Timestamp updated_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
google.protobuf.Timestamp updated_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||||
|
|
||||||
// Labels are arbitrary data on snapshots.
|
// Labels are arbitrary data on snapshots.
|
||||||
|
//
|
||||||
|
// The combined size of a key/value pair cannot exceed 4096 bytes.
|
||||||
map<string, string> labels = 6;
|
map<string, string> labels = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,10 +108,16 @@ var imagesSetLabelsCommand = cli.Command{
|
|||||||
Usage: "Set and clear labels for an image.",
|
Usage: "Set and clear labels for an image.",
|
||||||
ArgsUsage: "[flags] <name> [<key>=<value>, ...]",
|
ArgsUsage: "[flags] <name> [<key>=<value>, ...]",
|
||||||
Description: "Set and clear labels for an image.",
|
Description: "Set and clear labels for an image.",
|
||||||
Flags: []cli.Flag{},
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "replace-all, r",
|
||||||
|
Usage: "replace all labels",
|
||||||
|
},
|
||||||
|
},
|
||||||
Action: func(clicontext *cli.Context) error {
|
Action: func(clicontext *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
ctx, cancel = appContext(clicontext)
|
ctx, cancel = appContext(clicontext)
|
||||||
|
replaceAll = clicontext.Bool("replace-all")
|
||||||
name, labels = objectWithLabelArgs(clicontext)
|
name, labels = objectWithLabelArgs(clicontext)
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -131,7 +137,11 @@ var imagesSetLabelsCommand = cli.Command{
|
|||||||
)
|
)
|
||||||
|
|
||||||
for k := range labels {
|
for k := range labels {
|
||||||
fieldpaths = append(fieldpaths, strings.Join([]string{"labels", k}, "."))
|
if replaceAll {
|
||||||
|
fieldpaths = append(fieldpaths, "labels")
|
||||||
|
} else {
|
||||||
|
fieldpaths = append(fieldpaths, strings.Join([]string{"labels", k}, "."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image := images.Image{
|
image := images.Image{
|
||||||
|
23
labels/validate.go
Normal file
23
labels/validate.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package labels
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxSize = 4096
|
||||||
|
)
|
||||||
|
|
||||||
|
func Validate(k, v string) error {
|
||||||
|
// A label key and value should be under 4096 bytes
|
||||||
|
if (len(k) + len(v)) > maxSize {
|
||||||
|
if len(k) > 10 {
|
||||||
|
k = k[:10]
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "label key and value greater than maximum size (%d bytes), key: %s", maxSize, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
37
labels/validate_test.go
Normal file
37
labels/validate_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package labels
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidLabels(t *testing.T) {
|
||||||
|
shortStr := "s"
|
||||||
|
longStr := strings.Repeat("s", maxSize-1)
|
||||||
|
|
||||||
|
for key, value := range map[string]string{
|
||||||
|
"some": "value",
|
||||||
|
shortStr: longStr,
|
||||||
|
} {
|
||||||
|
if err := Validate(key, value); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v != nil", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidLabels(t *testing.T) {
|
||||||
|
addOneStr := "s"
|
||||||
|
maxSizeStr := strings.Repeat("s", maxSize)
|
||||||
|
|
||||||
|
for key, value := range map[string]string{
|
||||||
|
maxSizeStr: addOneStr,
|
||||||
|
} {
|
||||||
|
if err := Validate(key, value); err == nil {
|
||||||
|
t.Fatal("expected invalid error")
|
||||||
|
} else if !errdefs.IsInvalidArgument(err) {
|
||||||
|
t.Fatal("error should be an invalid label error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/filters"
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/identifiers"
|
"github.com/containerd/containerd/identifiers"
|
||||||
|
"github.com/containerd/containerd/labels"
|
||||||
"github.com/containerd/containerd/metadata/boltutil"
|
"github.com/containerd/containerd/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
@ -243,7 +244,13 @@ func validateContainer(container *containers.Container) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// labels and image have no validation
|
// image has no validation
|
||||||
|
for k, v := range container.Labels {
|
||||||
|
if err := labels.Validate(k, v); err == nil {
|
||||||
|
return errors.Wrapf(err, "containers.Labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if container.Runtime.Name == "" {
|
if container.Runtime.Name == "" {
|
||||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name must be set")
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name must be set")
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/filters"
|
"github.com/containerd/containerd/filters"
|
||||||
|
"github.com/containerd/containerd/labels"
|
||||||
"github.com/containerd/containerd/metadata/boltutil"
|
"github.com/containerd/containerd/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
@ -94,6 +95,9 @@ func (cs *contentStore) Update(ctx context.Context, info content.Info, fieldpath
|
|||||||
// Set mutable fields
|
// Set mutable fields
|
||||||
updated.Labels = info.Labels
|
updated.Labels = info.Labels
|
||||||
}
|
}
|
||||||
|
if err := validateInfo(&updated); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
updated.UpdatedAt = time.Now().UTC()
|
updated.UpdatedAt = time.Now().UTC()
|
||||||
return writeInfo(&updated, bkt)
|
return writeInfo(&updated, bkt)
|
||||||
@ -371,6 +375,10 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := validateInfo(&base); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
status, err := nw.Writer.Status()
|
status, err := nw.Writer.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -446,6 +454,16 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateInfo(info *content.Info) error {
|
||||||
|
for k, v := range info.Labels {
|
||||||
|
if err := labels.Validate(k, v); err == nil {
|
||||||
|
return errors.Wrapf(err, "info.Labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func readInfo(info *content.Info, bkt *bolt.Bucket) error {
|
func readInfo(info *content.Info, bkt *bolt.Bucket) error {
|
||||||
if err := boltutil.ReadTimestamps(bkt, &info.CreatedAt, &info.UpdatedAt); err != nil {
|
if err := boltutil.ReadTimestamps(bkt, &info.CreatedAt, &info.UpdatedAt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/filters"
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
|
"github.com/containerd/containerd/labels"
|
||||||
"github.com/containerd/containerd/metadata/boltutil"
|
"github.com/containerd/containerd/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
@ -101,6 +102,10 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
|
|||||||
return images.Image{}, errors.Wrapf(errdefs.ErrInvalidArgument, "image name is required for create")
|
return images.Image{}, errors.Wrapf(errdefs.ErrInvalidArgument, "image name is required for create")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateImage(&image); err != nil {
|
||||||
|
return images.Image{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return image, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
return image, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||||
ibkt, err := bkt.CreateBucket([]byte(image.Name))
|
ibkt, err := bkt.CreateBucket([]byte(image.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -170,6 +175,10 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths
|
|||||||
updated = image
|
updated = image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateImage(&image); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
updated.CreatedAt = createdat
|
updated.CreatedAt = createdat
|
||||||
updated.UpdatedAt = time.Now().UTC()
|
updated.UpdatedAt = time.Now().UTC()
|
||||||
return writeImage(ibkt, &updated)
|
return writeImage(ibkt, &updated)
|
||||||
@ -191,6 +200,16 @@ func (s *imageStore) Delete(ctx context.Context, name string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateImage(image *images.Image) error {
|
||||||
|
for k, v := range image.Labels {
|
||||||
|
if err := labels.Validate(k, v); err != nil {
|
||||||
|
return errors.Wrapf(err, "image.Labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func readImage(image *images.Image, bkt *bolt.Bucket) error {
|
func readImage(image *images.Image, bkt *bolt.Bucket) error {
|
||||||
if err := boltutil.ReadTimestamps(bkt, &image.CreatedAt, &image.UpdatedAt); err != nil {
|
if err := boltutil.ReadTimestamps(bkt, &image.CreatedAt, &image.UpdatedAt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
l "github.com/containerd/containerd/labels"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -27,6 +28,12 @@ func (s *namespaceStore) Create(ctx context.Context, namespace string, labels ma
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for k, v := range labels {
|
||||||
|
if err := l.Validate(k, v); err != nil {
|
||||||
|
return errors.Wrapf(err, "namespace.Labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// provides the already exists error.
|
// provides the already exists error.
|
||||||
bkt, err := topbkt.CreateBucket([]byte(namespace))
|
bkt, err := topbkt.CreateBucket([]byte(namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,6 +77,10 @@ func (s *namespaceStore) Labels(ctx context.Context, namespace string) (map[stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *namespaceStore) SetLabel(ctx context.Context, namespace, key, value string) error {
|
func (s *namespaceStore) SetLabel(ctx context.Context, namespace, key, value string) error {
|
||||||
|
if err := l.Validate(key, value); err != nil {
|
||||||
|
return errors.Wrapf(err, "namespace.Labels")
|
||||||
|
}
|
||||||
|
|
||||||
return withNamespacesLabelsBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
return withNamespacesLabelsBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return bkt.Delete([]byte(key))
|
return bkt.Delete([]byte(key))
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/containerd/containerd/labels"
|
||||||
"github.com/containerd/containerd/metadata/boltutil"
|
"github.com/containerd/containerd/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
@ -180,6 +181,9 @@ func (s *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths
|
|||||||
} else {
|
} else {
|
||||||
local.Labels = info.Labels
|
local.Labels = info.Labels
|
||||||
}
|
}
|
||||||
|
if err := validateSnapshot(&local); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
local.Updated = time.Now().UTC()
|
local.Updated = time.Now().UTC()
|
||||||
|
|
||||||
if err := boltutil.WriteTimestamps(sbkt, local.Created, local.Updated); err != nil {
|
if err := boltutil.WriteTimestamps(sbkt, local.Created, local.Updated); err != nil {
|
||||||
@ -257,6 +261,10 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateSnapshot(&base); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var m []mount.Mount
|
var m []mount.Mount
|
||||||
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||||
bkt, err := createSnapshotterBucket(tx, ns, s.name)
|
bkt, err := createSnapshotterBucket(tx, ns, s.name)
|
||||||
@ -328,6 +336,10 @@ func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateSnapshot(&base); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return update(ctx, s.db, func(tx *bolt.Tx) error {
|
return update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getSnapshotterBucket(tx, ns, s.name)
|
bkt := getSnapshotterBucket(tx, ns, s.name)
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -502,3 +514,13 @@ func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateSnapshot(info *snapshot.Info) error {
|
||||||
|
for k, v := range info.Labels {
|
||||||
|
if err := labels.Validate(k, v); err != nil {
|
||||||
|
return errors.Wrapf(err, "info.Labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -354,7 +354,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
|||||||
// 2. Compress inline.
|
// 2. Compress inline.
|
||||||
// 3. Validate digest and size (maybe).
|
// 3. Validate digest and size (maybe).
|
||||||
//
|
//
|
||||||
// Supporting these two paths is quite awkward but it let's both API
|
// Supporting these two paths is quite awkward but it lets both API
|
||||||
// users use the same writer style for each with a minimum of overhead.
|
// users use the same writer style for each with a minimum of overhead.
|
||||||
if req.Expected != "" {
|
if req.Expected != "" {
|
||||||
if expected != "" && expected != req.Expected {
|
if expected != "" && expected != req.Expected {
|
||||||
|
Loading…
Reference in New Issue
Block a user