diff --git a/schema/pod.go b/schema/pod.go index d4792ff3..507354bd 100644 --- a/schema/pod.go +++ b/schema/pod.go @@ -28,13 +28,15 @@ import ( const PodManifestKind = types.ACKind("PodManifest") type PodManifest struct { - ACVersion types.SemVer `json:"acVersion"` - ACKind types.ACKind `json:"acKind"` - Apps AppList `json:"apps"` - Volumes []types.Volume `json:"volumes"` - Isolators []types.Isolator `json:"isolators"` - Annotations types.Annotations `json:"annotations"` - Ports []types.ExposedPort `json:"ports"` + ACVersion types.SemVer `json:"acVersion"` + ACKind types.ACKind `json:"acKind"` + Apps AppList `json:"apps"` + Volumes []types.Volume `json:"volumes"` + Isolators []types.Isolator `json:"isolators"` + Annotations types.Annotations `json:"annotations"` + Ports []types.ExposedPort `json:"ports"` + CRIAnnotations types.CRIAnnotations `json:"criAnnotations,omitempty"` + CRILabels types.CRILabels `json:"criLabels,omitempty"` } // podManifest is a model to facilitate extra validation during the diff --git a/schema/types/app.go b/schema/types/app.go index a97ca025..88435f25 100644 --- a/schema/types/app.go +++ b/schema/types/app.go @@ -32,6 +32,8 @@ type App struct { MountPoints []MountPoint `json:"mountPoints,omitempty"` Ports []Port `json:"ports,omitempty"` Isolators Isolators `json:"isolators,omitempty"` + CRIAnnotations CRIAnnotations `json:"criAnnotations,omitempty"` + CRILabels CRILabels `json:"criLabels,omitempty"` } // app is a model to facilitate extra validation during the @@ -89,5 +91,8 @@ func (a *App) assertValid() error { if err := a.Isolators.assertValid(); err != nil { return err } + if err := a.CRILabels.assertValid(); err != nil { + return err + } return nil } diff --git a/schema/types/app_test.go b/schema/types/app_test.go index cd056d6c..14bdbed8 100644 --- a/schema/types/app_test.go +++ b/schema/types/app_test.go @@ -211,6 +211,29 @@ func TestAppUnmarshal(t *testing.T) { }, false, }, + { + `{"Exec":["/a"],"User":"0","Group":"0","CRIAnnotations":{"weird!":"normal?"},"CRILabels":{"one":"two"}}`, + &App{ + Exec: Exec{ + "/a", + }, + User: "0", + Group: "0", + Environment: make(Environment, 0), + CRIAnnotations: CRIAnnotations{ + "weird!": "normal?", + }, + CRILabels: CRILabels{ + "one": "two", + }, + }, + false, + }, + { + `{"Exec":["/a"],"User":"0","Group":"0","CRIAnnotations":{"weird!":"normal?"},"CRILabels":{"!one":"two"}}`, + &App{}, + true, + }, } for i, tt := range tests { a := &App{} diff --git a/schema/types/cri_annotations.go b/schema/types/cri_annotations.go new file mode 100644 index 00000000..51987604 --- /dev/null +++ b/schema/types/cri_annotations.go @@ -0,0 +1,18 @@ +// Copyright 2016 The appc 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 types + +// CRIAnnotations are arbitrary key-value pairs +type CRIAnnotations map[string]string diff --git a/schema/types/cri_labels.go b/schema/types/cri_labels.go new file mode 100644 index 00000000..7253b73f --- /dev/null +++ b/schema/types/cri_labels.go @@ -0,0 +1,31 @@ +// Copyright 2015 The appc 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 types + +import "fmt" + +type CRILabels map[ACIdentifier]string + +func (l CRILabels) assertValid() error { + for k, _ := range l { + if err := k.assertValid(); err != nil { + return err + } + if len(k) > 63 { + return fmt.Errorf(`label %q too long`, k) + } + } + return nil +} diff --git a/schema/types/cri_labels_test.go b/schema/types/cri_labels_test.go new file mode 100644 index 00000000..fdaf789b --- /dev/null +++ b/schema/types/cri_labels_test.go @@ -0,0 +1,52 @@ +// Copyright 2015 The appc 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 types + +import "testing" + +func TestCRILabelsAssertValid(t *testing.T) { + tests := []struct { + in CRILabels + werr bool + }{ + // empty is OK + { + CRILabels{}, + false, + }, + { + CRILabels{"a": "b"}, + false, + }, + { + CRILabels{"a!": "b"}, + true, + }, + { + CRILabels{"/a": "b"}, + true, + }, + { + CRILabels{"a/a": "b"}, + false, + }, + } + for i, tt := range tests { + err := tt.in.assertValid() + if gerr := (err != nil); gerr != tt.werr { + t.Errorf("#%d: gerr=%t, want %t (err=%v)", i, gerr, tt.werr, err) + } + } +} diff --git a/schema/types/mountpoint.go b/schema/types/mountpoint.go index 80eab945..7fb96e96 100644 --- a/schema/types/mountpoint.go +++ b/schema/types/mountpoint.go @@ -23,10 +23,14 @@ import ( "github.com/appc/spec/schema/common" ) +// MountPoint is the application-side manifestation of a Volume. +// The Volume is optional. If missing, the pod-level Volume of the +// same name shall be used type MountPoint struct { - Name ACName `json:"name"` - Path string `json:"path"` - ReadOnly bool `json:"readOnly,omitempty"` + Name ACName `json:"name"` + Path string `json:"path"` + ReadOnly bool `json:"readOnly,omitempty"` + Volume *Volume `json:"volume,omitempty"` } func (mount MountPoint) assertValid() error { diff --git a/schema/types/port.go b/schema/types/port.go index 78d6de4c..2d545150 100644 --- a/schema/types/port.go +++ b/schema/types/port.go @@ -18,12 +18,15 @@ import ( "encoding/json" "errors" "fmt" + "net" "net/url" "strconv" "github.com/appc/spec/schema/common" ) +// Port represents a port as offered by an application *inside* +// the pod. type Port struct { Name ACName `json:"name"` Protocol string `json:"protocol"` @@ -32,9 +35,14 @@ type Port struct { SocketActivated bool `json:"socketActivated"` } +// ExposedPort represents a port listening on the host side. +// The PodPort is optional -- if missing, then try and find the pod-side +// information by matching names type ExposedPort struct { Name ACName `json:"name"` HostPort uint `json:"hostPort"` + HostIP net.IP `json:"hostIP,omitempty"` // optional + PodPort *Port `json:"podPort,omitempty"` // optional. If missing, try and find a corresponding App's port } type port Port