Create a new internal object image/api.DockerImage which has two
versions, "1.0" and "pre012" to match the docker client and docker
registry API versioning. Allow the version of that API to be
passed when submitting an image - if not passed, assume that the
object is "1.0" (which is our legacy behavior). Clients should
set "apiVersion" inside the "DockerImageMetadata" field for maximum
forward compatibility to "1.0".
TODO: Upstream should allow the ability to decode and default a
kind and apiVersion for maximum flexibility.
| ... | ... |
@@ -19,6 +19,7 @@ import ( |
| 19 | 19 |
_ "github.com/openshift/origin/pkg/api/latest" |
| 20 | 20 |
"github.com/openshift/origin/pkg/api/v1beta1" |
| 21 | 21 |
config "github.com/openshift/origin/pkg/config/api" |
| 22 |
+ image "github.com/openshift/origin/pkg/image/api" |
|
| 22 | 23 |
template "github.com/openshift/origin/pkg/template/api" |
| 23 | 24 |
) |
| 24 | 25 |
|
| ... | ... |
@@ -78,6 +79,14 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs( |
| 78 | 78 |
// TODO: replace with structured type definition |
| 79 | 79 |
j.Items = []runtime.RawExtension{}
|
| 80 | 80 |
}, |
| 81 |
+ func(j *image.Image, c fuzz.Continue) {
|
|
| 82 |
+ c.Fuzz(&j.ObjectMeta) |
|
| 83 |
+ c.Fuzz(&j.DockerImageMetadata) |
|
| 84 |
+ j.DockerImageMetadata.APIVersion = "" |
|
| 85 |
+ j.DockerImageMetadata.Kind = "" |
|
| 86 |
+ j.DockerImageMetadataVersion = []string{"pre012", "1.0"}[c.Rand.Intn(2)]
|
|
| 87 |
+ j.DockerImageReference = c.RandString() |
|
| 88 |
+ }, |
|
| 81 | 89 |
func(j *config.Config, c fuzz.Continue) {
|
| 82 | 90 |
c.Fuzz(&j.ObjectMeta) |
| 83 | 91 |
// TODO: replace with structured type definition |
| ... | ... |
@@ -127,12 +136,12 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs( |
| 127 | 127 |
func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
| 128 | 128 |
name := reflect.TypeOf(source).Elem().Name() |
| 129 | 129 |
apiObjectFuzzer.Fuzz(source) |
| 130 |
- j, err := meta.Accessor(source) |
|
| 131 |
- if err != nil {
|
|
| 132 |
- t.Fatalf("Unexpected error %v for %#v", err, source)
|
|
| 130 |
+ if j, err := meta.TypeAccessor(source); err == nil {
|
|
| 131 |
+ j.SetKind("")
|
|
| 132 |
+ j.SetAPIVersion("")
|
|
| 133 |
+ } else {
|
|
| 134 |
+ t.Logf("Unable to set apiversion/kind to empty on %v", reflect.TypeOf(source))
|
|
| 133 | 135 |
} |
| 134 |
- j.SetKind("")
|
|
| 135 |
- j.SetAPIVersion("")
|
|
| 136 | 136 |
|
| 137 | 137 |
data, err := codec.Encode(source) |
| 138 | 138 |
if err != nil {
|
| ... | ... |
@@ -161,6 +170,10 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
| 161 | 161 |
} |
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 |
+var skipStandardVersions = map[string][]string{
|
|
| 165 |
+ "DockerImage": {"pre012", "1.0"},
|
|
| 166 |
+} |
|
| 167 |
+ |
|
| 164 | 168 |
func TestTypes(t *testing.T) {
|
| 165 | 169 |
for kind, reflectType := range api.Scheme.KnownTypes("") {
|
| 166 | 170 |
if !strings.Contains(reflectType.PkgPath(), "/origin/") {
|
| ... | ... |
@@ -174,8 +187,10 @@ func TestTypes(t *testing.T) {
|
| 174 | 174 |
t.Errorf("Couldn't make a %v? %v", kind, err)
|
| 175 | 175 |
continue |
| 176 | 176 |
} |
| 177 |
- if _, err := meta.Accessor(item); err != nil {
|
|
| 178 |
- t.Logf("%s is not a ObjectMeta and cannot be round tripped: %v", kind, err)
|
|
| 177 |
+ if versions, ok := skipStandardVersions[kind]; ok {
|
|
| 178 |
+ for _, v := range versions {
|
|
| 179 |
+ runTest(t, runtime.CodecFor(api.Scheme, v), item) |
|
| 180 |
+ } |
|
| 179 | 181 |
continue |
| 180 | 182 |
} |
| 181 | 183 |
runTest(t, v1beta1.Codec, item) |
| 182 | 184 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,55 @@ |
| 0 |
+package api |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/fsouza/go-dockerclient" |
|
| 4 |
+ |
|
| 5 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 6 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" |
|
| 7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func init() {
|
|
| 11 |
+ err := kapi.Scheme.AddConversionFuncs( |
|
| 12 |
+ // Convert docker client object to internal object |
|
| 13 |
+ func(in *docker.Image, out *DockerImage, s conversion.Scope) error {
|
|
| 14 |
+ if err := s.Convert(in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 15 |
+ return err |
|
| 16 |
+ } |
|
| 17 |
+ if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 18 |
+ return err |
|
| 19 |
+ } |
|
| 20 |
+ out.ID = in.ID |
|
| 21 |
+ out.Parent = in.Parent |
|
| 22 |
+ out.Comment = in.Comment |
|
| 23 |
+ out.Created = util.NewTime(in.Created) |
|
| 24 |
+ out.Container = in.Container |
|
| 25 |
+ out.DockerVersion = in.DockerVersion |
|
| 26 |
+ out.Author = in.Author |
|
| 27 |
+ out.Architecture = in.Architecture |
|
| 28 |
+ out.Size = in.Size |
|
| 29 |
+ return nil |
|
| 30 |
+ }, |
|
| 31 |
+ func(in *DockerImage, out *docker.Image, s conversion.Scope) error {
|
|
| 32 |
+ if err := s.Convert(&in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 33 |
+ return err |
|
| 34 |
+ } |
|
| 35 |
+ if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 36 |
+ return err |
|
| 37 |
+ } |
|
| 38 |
+ out.ID = in.ID |
|
| 39 |
+ out.Parent = in.Parent |
|
| 40 |
+ out.Comment = in.Comment |
|
| 41 |
+ out.Created = in.Created.Time |
|
| 42 |
+ out.Container = in.Container |
|
| 43 |
+ out.DockerVersion = in.DockerVersion |
|
| 44 |
+ out.Author = in.Author |
|
| 45 |
+ out.Architecture = in.Architecture |
|
| 46 |
+ out.Size = in.Size |
|
| 47 |
+ return nil |
|
| 48 |
+ }, |
|
| 49 |
+ ) |
|
| 50 |
+ if err != nil {
|
|
| 51 |
+ // If one of the conversion functions is malformed, detect it immediately. |
|
| 52 |
+ panic(err) |
|
| 53 |
+ } |
|
| 54 |
+} |
| 0 | 55 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,52 @@ |
| 0 |
+package docker10 |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 4 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// Image is the type representing a docker image and its various properties when |
|
| 8 |
+// retrieved from the Docker client API. |
|
| 9 |
+type DockerImage struct {
|
|
| 10 |
+ kapi.TypeMeta `json:",inline" yaml:",inline"` |
|
| 11 |
+ |
|
| 12 |
+ ID string `json:"Id" yaml:"Id"` |
|
| 13 |
+ Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty"` |
|
| 14 |
+ Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty"` |
|
| 15 |
+ Created util.Time `json:"Created,omitempty" yaml:"Created,omitempty"` |
|
| 16 |
+ Container string `json:"Container,omitempty" yaml:"Container,omitempty"` |
|
| 17 |
+ ContainerConfig DockerConfig `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty"` |
|
| 18 |
+ DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty"` |
|
| 19 |
+ Author string `json:"Author,omitempty" yaml:"Author,omitempty"` |
|
| 20 |
+ Config DockerConfig `json:"Config,omitempty" yaml:"Config,omitempty"` |
|
| 21 |
+ Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"` |
|
| 22 |
+ Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"` |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// DockerConfig is the list of configuration options used when creating a container. |
|
| 26 |
+type DockerConfig struct {
|
|
| 27 |
+ Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty"` |
|
| 28 |
+ Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty"` |
|
| 29 |
+ User string `json:"User,omitempty" yaml:"User,omitempty"` |
|
| 30 |
+ Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty"` |
|
| 31 |
+ MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty"` |
|
| 32 |
+ CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"` |
|
| 33 |
+ CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty"` |
|
| 34 |
+ AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty"` |
|
| 35 |
+ AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty"` |
|
| 36 |
+ AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty"` |
|
| 37 |
+ PortSpecs []string `json:"PortSpecs,omitempty" yaml:"PortSpecs,omitempty"` |
|
| 38 |
+ ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty" yaml:"ExposedPorts,omitempty"`
|
|
| 39 |
+ Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty"` |
|
| 40 |
+ OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty"` |
|
| 41 |
+ StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty"` |
|
| 42 |
+ Env []string `json:"Env,omitempty" yaml:"Env,omitempty"` |
|
| 43 |
+ Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty"` |
|
| 44 |
+ DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only |
|
| 45 |
+ Image string `json:"Image,omitempty" yaml:"Image,omitempty"` |
|
| 46 |
+ Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
|
|
| 47 |
+ VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"` |
|
| 48 |
+ WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty"` |
|
| 49 |
+ Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty"` |
|
| 50 |
+ NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty"` |
|
| 51 |
+} |
| 0 | 13 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,57 @@ |
| 0 |
+package dockerpre012 |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/fsouza/go-dockerclient" |
|
| 4 |
+ |
|
| 5 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 6 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" |
|
| 7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 8 |
+ |
|
| 9 |
+ newer "github.com/openshift/origin/pkg/image/api" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+func init() {
|
|
| 13 |
+ err := kapi.Scheme.AddConversionFuncs( |
|
| 14 |
+ // Convert docker client object to internal object, but only when this package is included |
|
| 15 |
+ func(in *docker.ImagePre012, out *newer.DockerImage, s conversion.Scope) error {
|
|
| 16 |
+ if err := s.Convert(in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 17 |
+ return err |
|
| 18 |
+ } |
|
| 19 |
+ if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 20 |
+ return err |
|
| 21 |
+ } |
|
| 22 |
+ out.ID = in.ID |
|
| 23 |
+ out.Parent = in.Parent |
|
| 24 |
+ out.Comment = in.Comment |
|
| 25 |
+ out.Created = util.NewTime(in.Created) |
|
| 26 |
+ out.Container = in.Container |
|
| 27 |
+ out.DockerVersion = in.DockerVersion |
|
| 28 |
+ out.Author = in.Author |
|
| 29 |
+ out.Architecture = in.Architecture |
|
| 30 |
+ out.Size = in.Size |
|
| 31 |
+ return nil |
|
| 32 |
+ }, |
|
| 33 |
+ func(in *newer.DockerImage, out *docker.ImagePre012, s conversion.Scope) error {
|
|
| 34 |
+ if err := s.Convert(&in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 35 |
+ return err |
|
| 36 |
+ } |
|
| 37 |
+ if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil {
|
|
| 38 |
+ return err |
|
| 39 |
+ } |
|
| 40 |
+ out.ID = in.ID |
|
| 41 |
+ out.Parent = in.Parent |
|
| 42 |
+ out.Comment = in.Comment |
|
| 43 |
+ out.Created = in.Created.Time |
|
| 44 |
+ out.Container = in.Container |
|
| 45 |
+ out.DockerVersion = in.DockerVersion |
|
| 46 |
+ out.Author = in.Author |
|
| 47 |
+ out.Architecture = in.Architecture |
|
| 48 |
+ out.Size = in.Size |
|
| 49 |
+ return nil |
|
| 50 |
+ }, |
|
| 51 |
+ ) |
|
| 52 |
+ if err != nil {
|
|
| 53 |
+ // If one of the conversion functions is malformed, detect it immediately. |
|
| 54 |
+ panic(err) |
|
| 55 |
+ } |
|
| 56 |
+} |
| 0 | 57 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,52 @@ |
| 0 |
+package dockerpre012 |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 4 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// DockerImage is for earlier versions of the Docker API (pre-012 to be specific). It is also the |
|
| 8 |
+// version of metadata that the Docker registry uses to persist metadata. |
|
| 9 |
+type DockerImage struct {
|
|
| 10 |
+ kapi.TypeMeta `json:",inline" yaml:",inline"` |
|
| 11 |
+ |
|
| 12 |
+ ID string `json:"id"` |
|
| 13 |
+ Parent string `json:"parent,omitempty"` |
|
| 14 |
+ Comment string `json:"comment,omitempty"` |
|
| 15 |
+ Created util.Time `json:"created"` |
|
| 16 |
+ Container string `json:"container,omitempty"` |
|
| 17 |
+ ContainerConfig DockerConfig `json:"container_config,omitempty"` |
|
| 18 |
+ DockerVersion string `json:"docker_version,omitempty"` |
|
| 19 |
+ Author string `json:"author,omitempty"` |
|
| 20 |
+ Config DockerConfig `json:"config,omitempty"` |
|
| 21 |
+ Architecture string `json:"architecture,omitempty"` |
|
| 22 |
+ Size int64 `json:"size,omitempty"` |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// DockerConfig is the list of configuration options used when creating a container. |
|
| 26 |
+type DockerConfig struct {
|
|
| 27 |
+ Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty"` |
|
| 28 |
+ Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty"` |
|
| 29 |
+ User string `json:"User,omitempty" yaml:"User,omitempty"` |
|
| 30 |
+ Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty"` |
|
| 31 |
+ MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty"` |
|
| 32 |
+ CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"` |
|
| 33 |
+ CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty"` |
|
| 34 |
+ AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty"` |
|
| 35 |
+ AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty"` |
|
| 36 |
+ AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty"` |
|
| 37 |
+ PortSpecs []string `json:"PortSpecs,omitempty" yaml:"PortSpecs,omitempty"` |
|
| 38 |
+ ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty" yaml:"ExposedPorts,omitempty"`
|
|
| 39 |
+ Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty"` |
|
| 40 |
+ OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty"` |
|
| 41 |
+ StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty"` |
|
| 42 |
+ Env []string `json:"Env,omitempty" yaml:"Env,omitempty"` |
|
| 43 |
+ Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty"` |
|
| 44 |
+ DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only |
|
| 45 |
+ Image string `json:"Image,omitempty" yaml:"Image,omitempty"` |
|
| 46 |
+ Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
|
|
| 47 |
+ VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"` |
|
| 48 |
+ WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty"` |
|
| 49 |
+ Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty"` |
|
| 50 |
+ NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty"` |
|
| 51 |
+} |
| 0 | 13 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,52 @@ |
| 0 |
+package api |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 4 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// Image is the type representing a docker image and its various properties when |
|
| 8 |
+// retrieved from the Docker client API. |
|
| 9 |
+type DockerImage struct {
|
|
| 10 |
+ kapi.TypeMeta `json:",inline" yaml:",inline"` |
|
| 11 |
+ |
|
| 12 |
+ ID string `json:"Id" yaml:"Id"` |
|
| 13 |
+ Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty"` |
|
| 14 |
+ Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty"` |
|
| 15 |
+ Created util.Time `json:"Created,omitempty" yaml:"Created,omitempty"` |
|
| 16 |
+ Container string `json:"Container,omitempty" yaml:"Container,omitempty"` |
|
| 17 |
+ ContainerConfig DockerConfig `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty"` |
|
| 18 |
+ DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty"` |
|
| 19 |
+ Author string `json:"Author,omitempty" yaml:"Author,omitempty"` |
|
| 20 |
+ Config DockerConfig `json:"Config,omitempty" yaml:"Config,omitempty"` |
|
| 21 |
+ Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"` |
|
| 22 |
+ Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"` |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// DockerConfig is the list of configuration options used when creating a container. |
|
| 26 |
+type DockerConfig struct {
|
|
| 27 |
+ Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty"` |
|
| 28 |
+ Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty"` |
|
| 29 |
+ User string `json:"User,omitempty" yaml:"User,omitempty"` |
|
| 30 |
+ Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty"` |
|
| 31 |
+ MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty"` |
|
| 32 |
+ CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"` |
|
| 33 |
+ CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty"` |
|
| 34 |
+ AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty"` |
|
| 35 |
+ AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty"` |
|
| 36 |
+ AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty"` |
|
| 37 |
+ PortSpecs []string `json:"PortSpecs,omitempty" yaml:"PortSpecs,omitempty"` |
|
| 38 |
+ ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty" yaml:"ExposedPorts,omitempty"`
|
|
| 39 |
+ Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty"` |
|
| 40 |
+ OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty"` |
|
| 41 |
+ StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty"` |
|
| 42 |
+ Env []string `json:"Env,omitempty" yaml:"Env,omitempty"` |
|
| 43 |
+ Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty"` |
|
| 44 |
+ DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only |
|
| 45 |
+ Image string `json:"Image,omitempty" yaml:"Image,omitempty"` |
|
| 46 |
+ Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
|
|
| 47 |
+ VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"` |
|
| 48 |
+ WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty"` |
|
| 49 |
+ Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty"` |
|
| 50 |
+ NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty"` |
|
| 51 |
+} |
| ... | ... |
@@ -11,6 +11,7 @@ func init() {
|
| 11 | 11 |
&ImageRepository{},
|
| 12 | 12 |
&ImageRepositoryList{},
|
| 13 | 13 |
&ImageRepositoryMapping{},
|
| 14 |
+ &DockerImage{},
|
|
| 14 | 15 |
) |
| 15 | 16 |
} |
| 16 | 17 |
|
| ... | ... |
@@ -19,3 +20,4 @@ func (*ImageList) IsAnAPIObject() {}
|
| 19 | 19 |
func (*ImageRepository) IsAnAPIObject() {}
|
| 20 | 20 |
func (*ImageRepositoryList) IsAnAPIObject() {}
|
| 21 | 21 |
func (*ImageRepositoryMapping) IsAnAPIObject() {}
|
| 22 |
+func (*DockerImage) IsAnAPIObject() {}
|
| ... | ... |
@@ -2,7 +2,6 @@ package api |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
| 5 |
- "github.com/fsouza/go-dockerclient" |
|
| 6 | 5 |
) |
| 7 | 6 |
|
| 8 | 7 |
// ImageList is a list of Image objects. |
| ... | ... |
@@ -21,7 +20,9 @@ type Image struct {
|
| 21 | 21 |
// The string that can be used to pull this image. |
| 22 | 22 |
DockerImageReference string `json:"dockerImageReference,omitempty" yaml:"dockerImageReference,omitempty"` |
| 23 | 23 |
// Metadata about this image |
| 24 |
- DockerImageMetadata docker.Image `json:"dockerImageMetadata,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 24 |
+ DockerImageMetadata DockerImage `json:"dockerImageMetadata,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 25 |
+ // This attribute conveys the version of docker metadata the JSON should be stored in, which if empty defaults to "1.0" |
|
| 26 |
+ DockerImageMetadataVersion string `json:"dockerImageMetadataVersion,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 25 | 27 |
} |
| 26 | 28 |
|
| 27 | 29 |
// ImageRepositoryList is a list of ImageRepository objects. |
| 28 | 30 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,66 @@ |
| 0 |
+package v1beta1 |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 4 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" |
|
| 5 |
+ |
|
| 6 |
+ newer "github.com/openshift/origin/pkg/image/api" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func init() {
|
|
| 10 |
+ err := kapi.Scheme.AddConversionFuncs( |
|
| 11 |
+ // The docker metadat must be cast to a version |
|
| 12 |
+ func(in *newer.Image, out *Image, s conversion.Scope) error {
|
|
| 13 |
+ if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
|
| 14 |
+ return err |
|
| 15 |
+ } |
|
| 16 |
+ |
|
| 17 |
+ out.DockerImageReference = in.DockerImageReference |
|
| 18 |
+ |
|
| 19 |
+ version := in.DockerImageMetadataVersion |
|
| 20 |
+ if len(version) == 0 {
|
|
| 21 |
+ version = "1.0" |
|
| 22 |
+ } |
|
| 23 |
+ data, err := kapi.Scheme.EncodeToVersion(&in.DockerImageMetadata, version) |
|
| 24 |
+ if err != nil {
|
|
| 25 |
+ return err |
|
| 26 |
+ } |
|
| 27 |
+ out.DockerImageMetadata.RawJSON = data |
|
| 28 |
+ out.DockerImageMetadataVersion = version |
|
| 29 |
+ |
|
| 30 |
+ return nil |
|
| 31 |
+ }, |
|
| 32 |
+ func(in *Image, out *newer.Image, s conversion.Scope) error {
|
|
| 33 |
+ if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
|
| 34 |
+ return err |
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ out.DockerImageReference = in.DockerImageReference |
|
| 38 |
+ |
|
| 39 |
+ version := in.DockerImageMetadataVersion |
|
| 40 |
+ if len(version) == 0 {
|
|
| 41 |
+ version = "1.0" |
|
| 42 |
+ } |
|
| 43 |
+ if len(in.DockerImageMetadata.RawJSON) > 0 {
|
|
| 44 |
+ // TODO: add a way to default the expected kind and version of an object if not set |
|
| 45 |
+ obj, err := kapi.Scheme.New(version, "DockerImage") |
|
| 46 |
+ if err != nil {
|
|
| 47 |
+ return err |
|
| 48 |
+ } |
|
| 49 |
+ if err := kapi.Scheme.DecodeInto(in.DockerImageMetadata.RawJSON, obj); err != nil {
|
|
| 50 |
+ return err |
|
| 51 |
+ } |
|
| 52 |
+ if err := s.Convert(obj, &out.DockerImageMetadata, 0); err != nil {
|
|
| 53 |
+ return err |
|
| 54 |
+ } |
|
| 55 |
+ } |
|
| 56 |
+ out.DockerImageMetadataVersion = version |
|
| 57 |
+ |
|
| 58 |
+ return nil |
|
| 59 |
+ }, |
|
| 60 |
+ ) |
|
| 61 |
+ if err != nil {
|
|
| 62 |
+ // If one of the conversion functions is malformed, detect it immediately. |
|
| 63 |
+ panic(err) |
|
| 64 |
+ } |
|
| 65 |
+} |
| 0 | 66 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,88 @@ |
| 0 |
+package v1beta1_test |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "reflect" |
|
| 4 |
+ "testing" |
|
| 5 |
+ |
|
| 6 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 8 |
+ "github.com/fsouza/go-dockerclient" |
|
| 9 |
+ |
|
| 10 |
+ _ "github.com/openshift/origin/pkg/api/latest" |
|
| 11 |
+ newer "github.com/openshift/origin/pkg/image/api" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+var Convert = kapi.Scheme.Convert |
|
| 15 |
+ |
|
| 16 |
+func TestRoundTripVersionedObject(t *testing.T) {
|
|
| 17 |
+ d := &newer.DockerImage{
|
|
| 18 |
+ Config: newer.DockerConfig{
|
|
| 19 |
+ Env: []string{"A=1", "B=2"},
|
|
| 20 |
+ }, |
|
| 21 |
+ } |
|
| 22 |
+ i := &newer.Image{
|
|
| 23 |
+ ObjectMeta: kapi.ObjectMeta{Name: "foo"},
|
|
| 24 |
+ |
|
| 25 |
+ DockerImageMetadata: *d, |
|
| 26 |
+ DockerImageReference: "foo/bar/baz", |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ data, err := kapi.Scheme.EncodeToVersion(i, "v1beta1") |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ obj, err := kapi.Scheme.Decode(data) |
|
| 35 |
+ if err != nil {
|
|
| 36 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 37 |
+ } |
|
| 38 |
+ image := obj.(*newer.Image) |
|
| 39 |
+ if image.DockerImageMetadataVersion != "1.0" {
|
|
| 40 |
+ t.Errorf("did not default to correct metadata version: %#v", image)
|
|
| 41 |
+ } |
|
| 42 |
+ image.DockerImageMetadataVersion = "" |
|
| 43 |
+ if !reflect.DeepEqual(i, image) {
|
|
| 44 |
+ t.Errorf("unable to round trip object: %s", util.ObjectDiff(i, image))
|
|
| 45 |
+ } |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+// This tests that JSON generated by an older version of v1beta1 still correctly parses and versions |
|
| 49 |
+func TestDecodeExistingAPIObjects(t *testing.T) {
|
|
| 50 |
+ obj, err := kapi.Scheme.Decode([]byte(`{
|
|
| 51 |
+ "kind":"Image", |
|
| 52 |
+ "apiVersion":"v1beta1", |
|
| 53 |
+ "metadata":{
|
|
| 54 |
+ "name":"foo" |
|
| 55 |
+ }, |
|
| 56 |
+ "dockerImageReference":"foo/bar/baz", |
|
| 57 |
+ "dockerImageMetadata":{
|
|
| 58 |
+ "Id":"0001", |
|
| 59 |
+ "Config":{
|
|
| 60 |
+ "Env":["A=1","B=2"] |
|
| 61 |
+ } |
|
| 62 |
+ } |
|
| 63 |
+ }`)) |
|
| 64 |
+ if err != nil {
|
|
| 65 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 66 |
+ } |
|
| 67 |
+ image := obj.(*newer.Image) |
|
| 68 |
+ if image.Name != "foo" || image.DockerImageReference != "foo/bar/baz" || image.DockerImageMetadata.ID != "0001" || image.DockerImageMetadata.Config.Env[0] != "A=1" {
|
|
| 69 |
+ t.Errorf("unexpected object: %#v", image)
|
|
| 70 |
+ } |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+func TestDecodeDockerRegistryJSON(t *testing.T) {
|
|
| 74 |
+ oldImage := docker.ImagePre012{
|
|
| 75 |
+ ID: "something", |
|
| 76 |
+ Config: &docker.Config{
|
|
| 77 |
+ Env: []string{"A=1", "B=2"},
|
|
| 78 |
+ }, |
|
| 79 |
+ } |
|
| 80 |
+ newImage := newer.DockerImage{}
|
|
| 81 |
+ if err := kapi.Scheme.Convert(&oldImage, &newImage); err != nil {
|
|
| 82 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 83 |
+ } |
|
| 84 |
+ if newImage.ID != "something" || newImage.Config.Env[0] != "A=1" {
|
|
| 85 |
+ t.Errorf("unexpected object: %#v", newImage)
|
|
| 86 |
+ } |
|
| 87 |
+} |
| ... | ... |
@@ -2,7 +2,7 @@ package v1beta1 |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" |
| 5 |
- "github.com/fsouza/go-dockerclient" |
|
| 5 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
|
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 | 8 |
// ImageList is a list of Image objects. |
| ... | ... |
@@ -21,7 +21,9 @@ type Image struct {
|
| 21 | 21 |
// The string that can be used to pull this image. |
| 22 | 22 |
DockerImageReference string `json:"dockerImageReference,omitempty" yaml:"dockerImageReference,omitempty"` |
| 23 | 23 |
// Metadata about this image |
| 24 |
- DockerImageMetadata docker.Image `json:"dockerImageMetadata,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 24 |
+ DockerImageMetadata runtime.RawExtension `json:"dockerImageMetadata,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 25 |
+ // This attribute conveys the version of the object, which if empty defaults to "1.0" |
|
| 26 |
+ DockerImageMetadataVersion string `json:"dockerImageMetadataVersion,omitempty" yaml:"dockerImageMetadata,omitempty"` |
|
| 25 | 27 |
} |
| 26 | 28 |
|
| 27 | 29 |
// ImageRepositoryList is a list of ImageRepository objects. |
| ... | ... |
@@ -12,9 +12,9 @@ import ( |
| 12 | 12 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" |
| 13 | 13 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
| 14 | 14 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
| 15 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
| 15 | 16 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" |
| 16 | 17 |
"github.com/coreos/go-etcd/etcd" |
| 17 |
- "github.com/fsouza/go-dockerclient" |
|
| 18 | 18 |
|
| 19 | 19 |
"github.com/openshift/origin/pkg/api/latest" |
| 20 | 20 |
"github.com/openshift/origin/pkg/image/api" |
| ... | ... |
@@ -216,7 +216,7 @@ func TestEtcdCreateImage(t *testing.T) {
|
| 216 | 216 |
Name: "foo", |
| 217 | 217 |
}, |
| 218 | 218 |
DockerImageReference: "openshift/ruby-19-centos", |
| 219 |
- DockerImageMetadata: docker.Image{
|
|
| 219 |
+ DockerImageMetadata: api.DockerImage{
|
|
| 220 | 220 |
ID: "abc123", |
| 221 | 221 |
}, |
| 222 | 222 |
}) |
| ... | ... |
@@ -343,9 +343,9 @@ func TestEtcdWatchImagesOK(t *testing.T) {
|
| 343 | 343 |
{
|
| 344 | 344 |
labels.Everything(), |
| 345 | 345 |
[]*api.Image{
|
| 346 |
- {ObjectMeta: kapi.ObjectMeta{Name: "a"}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 347 |
- {ObjectMeta: kapi.ObjectMeta{Name: "b"}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 348 |
- {ObjectMeta: kapi.ObjectMeta{Name: "c"}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 346 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "a"}, DockerImageMetadata: api.DockerImage{}},
|
|
| 347 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "b"}, DockerImageMetadata: api.DockerImage{}},
|
|
| 348 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "c"}, DockerImageMetadata: api.DockerImage{}},
|
|
| 349 | 349 |
}, |
| 350 | 350 |
[]bool{
|
| 351 | 351 |
true, |
| ... | ... |
@@ -356,9 +356,9 @@ func TestEtcdWatchImagesOK(t *testing.T) {
|
| 356 | 356 |
{
|
| 357 | 357 |
labels.SelectorFromSet(labels.Set{"color": "blue"}),
|
| 358 | 358 |
[]*api.Image{
|
| 359 |
- {ObjectMeta: kapi.ObjectMeta{Name: "a", Labels: map[string]string{"color": "blue"}}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 360 |
- {ObjectMeta: kapi.ObjectMeta{Name: "b", Labels: map[string]string{"color": "green"}}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 361 |
- {ObjectMeta: kapi.ObjectMeta{Name: "c", Labels: map[string]string{"color": "blue"}}, DockerImageMetadata: docker.Image{Created: time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)}},
|
|
| 359 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "a", Labels: map[string]string{"color": "blue"}}, DockerImageMetadata: api.DockerImage{}},
|
|
| 360 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "b", Labels: map[string]string{"color": "green"}}, DockerImageMetadata: api.DockerImage{}},
|
|
| 361 |
+ {ObjectMeta: kapi.ObjectMeta{Name: "c", Labels: map[string]string{"color": "blue"}}, DockerImageMetadata: api.DockerImage{}},
|
|
| 362 | 362 |
}, |
| 363 | 363 |
[]bool{
|
| 364 | 364 |
true, |
| ... | ... |
@@ -394,8 +394,9 @@ func TestEtcdWatchImagesOK(t *testing.T) {
|
| 394 | 394 |
if e, a := watch.Added, event.Type; e != a {
|
| 395 | 395 |
t.Errorf("Expected %v, got %v", e, a)
|
| 396 | 396 |
} |
| 397 |
+ image.DockerImageMetadataVersion = "1.0" |
|
| 397 | 398 |
if e, a := image, event.Object; !reflect.DeepEqual(e, a) {
|
| 398 |
- t.Errorf("Expected %v, got %v", e, a)
|
|
| 399 |
+ t.Errorf("Objects did not match: %s", util.ObjectDiff(e, a))
|
|
| 399 | 400 |
} |
| 400 | 401 |
case <-time.After(50 * time.Millisecond): |
| 401 | 402 |
if tt.expected[testIndex] {
|
| ... | ... |
@@ -11,7 +11,6 @@ import ( |
| 11 | 11 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" |
| 12 | 12 |
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
| 13 | 13 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" |
| 14 |
- "github.com/fsouza/go-dockerclient" |
|
| 15 | 14 |
|
| 16 | 15 |
"github.com/openshift/origin/pkg/image/api" |
| 17 | 16 |
"github.com/openshift/origin/pkg/image/registry/test" |
| ... | ... |
@@ -174,11 +173,11 @@ func TestCreateImageRepositoryMapping(t *testing.T) {
|
| 174 | 174 |
Name: "imageID1", |
| 175 | 175 |
}, |
| 176 | 176 |
DockerImageReference: "localhost:5000/someproject/somerepo:imageID1", |
| 177 |
- DockerImageMetadata: docker.Image{
|
|
| 178 |
- Config: &docker.Config{
|
|
| 177 |
+ DockerImageMetadata: api.DockerImage{
|
|
| 178 |
+ Config: api.DockerConfig{
|
|
| 179 | 179 |
Cmd: []string{"ls", "/"},
|
| 180 | 180 |
Env: []string{"a=1"},
|
| 181 |
- ExposedPorts: map[docker.Port]struct{}{"1234/tcp": {}},
|
|
| 181 |
+ ExposedPorts: map[string]struct{}{"1234/tcp": {}},
|
|
| 182 | 182 |
Memory: 1234, |
| 183 | 183 |
CPUShares: 99, |
| 184 | 184 |
WorkingDir: "/workingDir", |
| ... | ... |
@@ -240,11 +239,11 @@ func TestCreateImageRepositoryConflictingNamespace(t *testing.T) {
|
| 240 | 240 |
Name: "imageID1", |
| 241 | 241 |
}, |
| 242 | 242 |
DockerImageReference: "localhost:5000/someproject/somerepo:imageID1", |
| 243 |
- DockerImageMetadata: docker.Image{
|
|
| 244 |
- Config: &docker.Config{
|
|
| 243 |
+ DockerImageMetadata: api.DockerImage{
|
|
| 244 |
+ Config: api.DockerConfig{
|
|
| 245 | 245 |
Cmd: []string{"ls", "/"},
|
| 246 | 246 |
Env: []string{"a=1"},
|
| 247 |
- ExposedPorts: map[docker.Port]struct{}{"1234/tcp": {}},
|
|
| 247 |
+ ExposedPorts: map[string]struct{}{"1234/tcp": {}},
|
|
| 248 | 248 |
Memory: 1234, |
| 249 | 249 |
CPUShares: 99, |
| 250 | 250 |
WorkingDir: "/workingDir", |