Repository: appc/spec
Pull request #656 (2016-09-19 09:24:48)

Update appc data structures for CRI
@yifan-gu @lucab @s-urbaniak I also updated the appc spec for annotations, along with port forwards. Take a look and we can update glide to pull from appc/spec's CRI branch.


Patch:
diff --git a/schema/pod.go b/schema/pod.go
index d4792ff..507354b 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 a97ca02..88435f2 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/cri_annotations.go b/schema/types/cri_annotations.go
new file mode 100644
index 0000000..5198760
--- /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 0000000..7253b73
--- /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/mountpoint.go b/schema/types/mountpoint.go
index 80eab94..7fb96e9 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 78d6de4..2d54515 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


Test patch:
diff --git a/schema/types/app_test.go b/schema/types/app_test.go
index cd056d6..14bdbed 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_labels_test.go b/schema/types/cri_labels_test.go
new file mode 100644
index 0000000..fdaf789
--- /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)
+		}
+	}
+}