diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 7565987097f..5923135b555 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -225,6 +225,8 @@ func (s *APIServer) Run(_ []string) error { disableV1beta3 = true } + _, enableV1 := s.RuntimeConfig["api/v1"] + // TODO: expose same flags as client.BindClientConfigFlags but for a server clientConfig := &client.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), @@ -298,6 +300,7 @@ func (s *APIServer) Run(_ []string) error { Authorizer: authorizer, AdmissionControl: admissionController, DisableV1Beta3: disableV1beta3, + EnableV1: enableV1, MasterServiceNamespace: s.MasterServiceNamespace, ClusterName: s.ClusterName, ExternalHost: s.ExternalHost, diff --git a/pkg/api/latest/latest.go b/pkg/api/latest/latest.go index a58d44d437f..799e072c755 100644 --- a/pkg/api/latest/latest.go +++ b/pkg/api/latest/latest.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" @@ -40,7 +41,7 @@ const OldestVersion = "v1beta1" // may be assumed to be least feature rich to most feature rich, and clients may // choose to prefer the latter items in the list over the former items when presented // with a set of versions to choose. -var Versions = []string{"v1beta1", "v1beta2", "v1beta3"} +var Versions = []string{"v1beta1", "v1beta2", "v1beta3", "v1"} // Codec is the default codec for serializing output that should use // the latest supported version. Use this Codec when writing to @@ -86,6 +87,12 @@ func InterfacesFor(version string) (*meta.VersionInterfaces, error) { ObjectConvertor: api.Scheme, MetadataAccessor: accessor, }, nil + case "v1": + return &meta.VersionInterfaces{ + Codec: v1.Codec, + ObjectConvertor: api.Scheme, + MetadataAccessor: accessor, + }, nil default: return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(Versions, ", ")) } @@ -103,7 +110,7 @@ func init() { }, ) // list of versions we support on the server - versions := []string{"v1beta1", "v1beta2", "v1beta3"} + versions := []string{"v1beta1", "v1beta2", "v1beta3", "v1"} // versions that used mixed case URL formats versionMixedCase := map[string]bool{ @@ -116,6 +123,7 @@ func init() { "v1beta1": meta.RESTScopeNamespaceLegacy, "v1beta2": meta.RESTScopeNamespaceLegacy, "v1beta3": meta.RESTScopeNamespace, + "v1": meta.RESTScopeNamespace, } // the list of kinds that are scoped at the root of the api hierarchy diff --git a/pkg/api/v1/conversion.go b/pkg/api/v1/conversion.go new file mode 100644 index 00000000000..6cb2a39356c --- /dev/null +++ b/pkg/api/v1/conversion.go @@ -0,0 +1,2810 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1 + +import ( + "fmt" + + newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" + "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" +) + +func init() { + err := newer.Scheme.AddGeneratedConversionFuncs( + func(in *AWSElasticBlockStoreVolumeSource, out *newer.AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.AWSElasticBlockStoreVolumeSource, out *AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *Binding, out *newer.Binding, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Target, &out.Target, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Binding, out *Binding, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Target, &out.Target, 0); err != nil { + return err + } + return nil + }, + func(in *Capabilities, out *newer.Capabilities, s conversion.Scope) error { + if in.Add != nil { + out.Add = make([]newer.CapabilityType, len(in.Add)) + for i := range in.Add { + if err := s.Convert(&in.Add[i], &out.Add[i], 0); err != nil { + return err + } + } + } + if in.Drop != nil { + out.Drop = make([]newer.CapabilityType, len(in.Drop)) + for i := range in.Drop { + if err := s.Convert(&in.Drop[i], &out.Drop[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.Capabilities, out *Capabilities, s conversion.Scope) error { + if in.Add != nil { + out.Add = make([]CapabilityType, len(in.Add)) + for i := range in.Add { + if err := s.Convert(&in.Add[i], &out.Add[i], 0); err != nil { + return err + } + } + } + if in.Drop != nil { + out.Drop = make([]CapabilityType, len(in.Drop)) + for i := range in.Drop { + if err := s.Convert(&in.Drop[i], &out.Drop[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ComponentCondition, out *newer.ComponentCondition, s conversion.Scope) error { + out.Type = newer.ComponentConditionType(in.Type) + out.Status = newer.ConditionStatus(in.Status) + out.Message = in.Message + out.Error = in.Error + return nil + }, + func(in *newer.ComponentCondition, out *ComponentCondition, s conversion.Scope) error { + out.Type = ComponentConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + out.Message = in.Message + out.Error = in.Error + return nil + }, + func(in *ComponentStatus, out *newer.ComponentStatus, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Conditions != nil { + out.Conditions = make([]newer.ComponentCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.ComponentStatus, out *ComponentStatus, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Conditions != nil { + out.Conditions = make([]ComponentCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ComponentStatusList, out *newer.ComponentStatusList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.ComponentStatus, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.ComponentStatusList, out *ComponentStatusList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]ComponentStatus, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *Container, out *newer.Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + if in.Args != nil { + out.Args = make([]string, len(in.Args)) + for i := range in.Args { + out.Args[i] = in.Args[i] + } + } + out.WorkingDir = in.WorkingDir + if in.Ports != nil { + out.Ports = make([]newer.ContainerPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Env != nil { + out.Env = make([]newer.EnvVar, len(in.Env)) + for i := range in.Env { + if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + if in.VolumeMounts != nil { + out.VolumeMounts = make([]newer.VolumeMount, len(in.VolumeMounts)) + for i := range in.VolumeMounts { + if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { + return err + } + out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged + out.ImagePullPolicy = newer.PullPolicy(in.ImagePullPolicy) + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Container, out *Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + if in.Args != nil { + out.Args = make([]string, len(in.Args)) + for i := range in.Args { + out.Args[i] = in.Args[i] + } + } + out.WorkingDir = in.WorkingDir + if in.Ports != nil { + out.Ports = make([]ContainerPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Env != nil { + out.Env = make([]EnvVar, len(in.Env)) + for i := range in.Env { + if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + if in.VolumeMounts != nil { + out.VolumeMounts = make([]VolumeMount, len(in.VolumeMounts)) + for i := range in.VolumeMounts { + if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { + return err + } + out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged + out.ImagePullPolicy = PullPolicy(in.ImagePullPolicy) + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { + return err + } + return nil + }, + func(in *ContainerPort, out *newer.ContainerPort, s conversion.Scope) error { + out.Name = in.Name + out.HostPort = in.HostPort + out.ContainerPort = in.ContainerPort + out.Protocol = newer.Protocol(in.Protocol) + out.HostIP = in.HostIP + return nil + }, + func(in *newer.ContainerPort, out *ContainerPort, s conversion.Scope) error { + out.Name = in.Name + out.HostPort = in.HostPort + out.ContainerPort = in.ContainerPort + out.Protocol = Protocol(in.Protocol) + out.HostIP = in.HostIP + return nil + }, + func(in *ContainerState, out *newer.ContainerState, s conversion.Scope) error { + if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil { + return err + } + if err := s.Convert(&in.Running, &out.Running, 0); err != nil { + return err + } + if err := s.Convert(&in.Termination, &out.Termination, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ContainerState, out *ContainerState, s conversion.Scope) error { + if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil { + return err + } + if err := s.Convert(&in.Running, &out.Running, 0); err != nil { + return err + } + if err := s.Convert(&in.Termination, &out.Termination, 0); err != nil { + return err + } + return nil + }, + func(in *ContainerStateRunning, out *newer.ContainerStateRunning, s conversion.Scope) error { + if err := s.Convert(&in.StartedAt, &out.StartedAt, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ContainerStateRunning, out *ContainerStateRunning, s conversion.Scope) error { + if err := s.Convert(&in.StartedAt, &out.StartedAt, 0); err != nil { + return err + } + return nil + }, + func(in *ContainerStateTerminated, out *newer.ContainerStateTerminated, s conversion.Scope) error { + out.ExitCode = in.ExitCode + out.Signal = in.Signal + out.Reason = in.Reason + out.Message = in.Message + if err := s.Convert(&in.StartedAt, &out.StartedAt, 0); err != nil { + return err + } + if err := s.Convert(&in.FinishedAt, &out.FinishedAt, 0); err != nil { + return err + } + out.ContainerID = in.ContainerID + return nil + }, + func(in *newer.ContainerStateTerminated, out *ContainerStateTerminated, s conversion.Scope) error { + out.ExitCode = in.ExitCode + out.Signal = in.Signal + out.Reason = in.Reason + out.Message = in.Message + if err := s.Convert(&in.StartedAt, &out.StartedAt, 0); err != nil { + return err + } + if err := s.Convert(&in.FinishedAt, &out.FinishedAt, 0); err != nil { + return err + } + out.ContainerID = in.ContainerID + return nil + }, + func(in *ContainerStateWaiting, out *newer.ContainerStateWaiting, s conversion.Scope) error { + out.Reason = in.Reason + return nil + }, + func(in *newer.ContainerStateWaiting, out *ContainerStateWaiting, s conversion.Scope) error { + out.Reason = in.Reason + return nil + }, + func(in *ContainerStatus, out *newer.ContainerStatus, s conversion.Scope) error { + out.Name = in.Name + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + out.Ready = in.Ready + out.RestartCount = in.RestartCount + out.Image = in.Image + out.ImageID = in.ImageID + out.ContainerID = in.ContainerID + return nil + }, + func(in *newer.ContainerStatus, out *ContainerStatus, s conversion.Scope) error { + out.Name = in.Name + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + out.Ready = in.Ready + out.RestartCount = in.RestartCount + out.Image = in.Image + out.ImageID = in.ImageID + out.ContainerID = in.ContainerID + return nil + }, + func(in *DeleteOptions, out *newer.DeleteOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if in.GracePeriodSeconds != nil { + out.GracePeriodSeconds = new(int64) + *out.GracePeriodSeconds = *in.GracePeriodSeconds + } + return nil + }, + func(in *newer.DeleteOptions, out *DeleteOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if in.GracePeriodSeconds != nil { + out.GracePeriodSeconds = new(int64) + *out.GracePeriodSeconds = *in.GracePeriodSeconds + } + return nil + }, + func(in *EmptyDirVolumeSource, out *newer.EmptyDirVolumeSource, s conversion.Scope) error { + out.Medium = newer.StorageType(in.Medium) + return nil + }, + func(in *newer.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error { + out.Medium = StorageType(in.Medium) + return nil + }, + func(in *EndpointAddress, out *newer.EndpointAddress, s conversion.Scope) error { + out.IP = in.IP + if err := s.Convert(&in.TargetRef, &out.TargetRef, 0); err != nil { + return err + } + return nil + }, + func(in *newer.EndpointAddress, out *EndpointAddress, s conversion.Scope) error { + out.IP = in.IP + if err := s.Convert(&in.TargetRef, &out.TargetRef, 0); err != nil { + return err + } + return nil + }, + func(in *EndpointPort, out *newer.EndpointPort, s conversion.Scope) error { + out.Name = in.Name + out.Port = in.Port + out.Protocol = newer.Protocol(in.Protocol) + return nil + }, + func(in *newer.EndpointPort, out *EndpointPort, s conversion.Scope) error { + out.Name = in.Name + out.Port = in.Port + out.Protocol = Protocol(in.Protocol) + return nil + }, + func(in *EndpointSubset, out *newer.EndpointSubset, s conversion.Scope) error { + if in.Addresses != nil { + out.Addresses = make([]newer.EndpointAddress, len(in.Addresses)) + for i := range in.Addresses { + if err := s.Convert(&in.Addresses[i], &out.Addresses[i], 0); err != nil { + return err + } + } + } + if in.Ports != nil { + out.Ports = make([]newer.EndpointPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.EndpointSubset, out *EndpointSubset, s conversion.Scope) error { + if in.Addresses != nil { + out.Addresses = make([]EndpointAddress, len(in.Addresses)) + for i := range in.Addresses { + if err := s.Convert(&in.Addresses[i], &out.Addresses[i], 0); err != nil { + return err + } + } + } + if in.Ports != nil { + out.Ports = make([]EndpointPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *Endpoints, out *newer.Endpoints, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Subsets != nil { + out.Subsets = make([]newer.EndpointSubset, len(in.Subsets)) + for i := range in.Subsets { + if err := s.Convert(&in.Subsets[i], &out.Subsets[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.Endpoints, out *Endpoints, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Subsets != nil { + out.Subsets = make([]EndpointSubset, len(in.Subsets)) + for i := range in.Subsets { + if err := s.Convert(&in.Subsets[i], &out.Subsets[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *EndpointsList, out *newer.EndpointsList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Endpoints, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.EndpointsList, out *EndpointsList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Endpoints, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil + }, + func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil + }, + func(in *Event, out *newer.Event, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + if err := s.Convert(&in.Source, &out.Source, 0); err != nil { + return err + } + if err := s.Convert(&in.FirstTimestamp, &out.FirstTimestamp, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTimestamp, &out.LastTimestamp, 0); err != nil { + return err + } + out.Count = in.Count + return nil + }, + func(in *newer.Event, out *Event, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + if err := s.Convert(&in.Source, &out.Source, 0); err != nil { + return err + } + if err := s.Convert(&in.FirstTimestamp, &out.FirstTimestamp, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTimestamp, &out.LastTimestamp, 0); err != nil { + return err + } + out.Count = in.Count + return nil + }, + func(in *EventList, out *newer.EventList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Event, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.EventList, out *EventList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Event, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *EventSource, out *newer.EventSource, s conversion.Scope) error { + out.Component = in.Component + out.Host = in.Host + return nil + }, + func(in *newer.EventSource, out *EventSource, s conversion.Scope) error { + out.Component = in.Component + out.Host = in.Host + return nil + }, + func(in *ExecAction, out *newer.ExecAction, s conversion.Scope) error { + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + return nil + }, + func(in *newer.ExecAction, out *ExecAction, s conversion.Scope) error { + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + return nil + }, + func(in *GCEPersistentDiskVolumeSource, out *newer.GCEPersistentDiskVolumeSource, s conversion.Scope) error { + out.PDName = in.PDName + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.GCEPersistentDiskVolumeSource, out *GCEPersistentDiskVolumeSource, s conversion.Scope) error { + out.PDName = in.PDName + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *GitRepoVolumeSource, out *newer.GitRepoVolumeSource, s conversion.Scope) error { + out.Repository = in.Repository + out.Revision = in.Revision + return nil + }, + func(in *newer.GitRepoVolumeSource, out *GitRepoVolumeSource, s conversion.Scope) error { + out.Repository = in.Repository + out.Revision = in.Revision + return nil + }, + func(in *GlusterfsVolumeSource, out *newer.GlusterfsVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.GlusterfsVolumeSource, out *GlusterfsVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *HTTPGetAction, out *newer.HTTPGetAction, s conversion.Scope) error { + out.Path = in.Path + if err := s.Convert(&in.Port, &out.Port, 0); err != nil { + return err + } + out.Host = in.Host + return nil + }, + func(in *newer.HTTPGetAction, out *HTTPGetAction, s conversion.Scope) error { + out.Path = in.Path + if err := s.Convert(&in.Port, &out.Port, 0); err != nil { + return err + } + out.Host = in.Host + return nil + }, + func(in *Handler, out *newer.Handler, s conversion.Scope) error { + if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { + return err + } + if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { + return err + } + if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Handler, out *Handler, s conversion.Scope) error { + if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { + return err + } + if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { + return err + } + if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { + return err + } + return nil + }, + func(in *HostPathVolumeSource, out *newer.HostPathVolumeSource, s conversion.Scope) error { + out.Path = in.Path + return nil + }, + func(in *newer.HostPathVolumeSource, out *HostPathVolumeSource, s conversion.Scope) error { + out.Path = in.Path + return nil + }, + func(in *ISCSIVolumeSource, out *newer.ISCSIVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.ISCSIVolumeSource, out *ISCSIVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *Lifecycle, out *newer.Lifecycle, s conversion.Scope) error { + if err := s.Convert(&in.PostStart, &out.PostStart, 0); err != nil { + return err + } + if err := s.Convert(&in.PreStop, &out.PreStop, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Lifecycle, out *Lifecycle, s conversion.Scope) error { + if err := s.Convert(&in.PostStart, &out.PostStart, 0); err != nil { + return err + } + if err := s.Convert(&in.PreStop, &out.PreStop, 0); err != nil { + return err + } + return nil + }, + func(in *LimitRange, out *newer.LimitRange, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil + }, + func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil + }, + func(in *LimitRangeItem, out *newer.LimitRangeItem, s conversion.Scope) error { + out.Type = newer.LimitType(in.Type) + if in.Max != nil { + out.Max = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Max { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Max[newer.ResourceName(key)] = newVal + } + } + if in.Min != nil { + out.Min = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Min { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Min[newer.ResourceName(key)] = newVal + } + } + if in.Default != nil { + out.Default = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Default { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Default[newer.ResourceName(key)] = newVal + } + } + return nil + }, + func(in *newer.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error { + out.Type = LimitType(in.Type) + if in.Max != nil { + out.Max = make(map[ResourceName]resource.Quantity) + for key, val := range in.Max { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Max[ResourceName(key)] = newVal + } + } + if in.Min != nil { + out.Min = make(map[ResourceName]resource.Quantity) + for key, val := range in.Min { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Min[ResourceName(key)] = newVal + } + } + if in.Default != nil { + out.Default = make(map[ResourceName]resource.Quantity) + for key, val := range in.Default { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Default[ResourceName(key)] = newVal + } + } + return nil + }, + func(in *LimitRangeList, out *newer.LimitRangeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.LimitRange, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.LimitRangeList, out *LimitRangeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]LimitRange, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *LimitRangeSpec, out *newer.LimitRangeSpec, s conversion.Scope) error { + if in.Limits != nil { + out.Limits = make([]newer.LimitRangeItem, len(in.Limits)) + for i := range in.Limits { + if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error { + if in.Limits != nil { + out.Limits = make([]LimitRangeItem, len(in.Limits)) + for i := range in.Limits { + if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ListMeta, out *newer.ListMeta, s conversion.Scope) error { + out.SelfLink = in.SelfLink + out.ResourceVersion = in.ResourceVersion + return nil + }, + func(in *newer.ListMeta, out *ListMeta, s conversion.Scope) error { + out.SelfLink = in.SelfLink + out.ResourceVersion = in.ResourceVersion + return nil + }, + func(in *NFSVolumeSource, out *newer.NFSVolumeSource, s conversion.Scope) error { + out.Server = in.Server + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.NFSVolumeSource, out *NFSVolumeSource, s conversion.Scope) error { + out.Server = in.Server + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *Namespace, out *newer.Namespace, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Namespace, out *Namespace, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *NamespaceList, out *newer.NamespaceList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Namespace, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.NamespaceList, out *NamespaceList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Namespace, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *NamespaceSpec, out *newer.NamespaceSpec, s conversion.Scope) error { + if in.Finalizers != nil { + out.Finalizers = make([]newer.FinalizerName, len(in.Finalizers)) + for i := range in.Finalizers { + if err := s.Convert(&in.Finalizers[i], &out.Finalizers[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.NamespaceSpec, out *NamespaceSpec, s conversion.Scope) error { + if in.Finalizers != nil { + out.Finalizers = make([]FinalizerName, len(in.Finalizers)) + for i := range in.Finalizers { + if err := s.Convert(&in.Finalizers[i], &out.Finalizers[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *NamespaceStatus, out *newer.NamespaceStatus, s conversion.Scope) error { + out.Phase = newer.NamespacePhase(in.Phase) + return nil + }, + func(in *newer.NamespaceStatus, out *NamespaceStatus, s conversion.Scope) error { + out.Phase = NamespacePhase(in.Phase) + return nil + }, + func(in *Node, out *newer.Node, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Node, out *Node, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *NodeAddress, out *newer.NodeAddress, s conversion.Scope) error { + out.Type = newer.NodeAddressType(in.Type) + out.Address = in.Address + return nil + }, + func(in *newer.NodeAddress, out *NodeAddress, s conversion.Scope) error { + out.Type = NodeAddressType(in.Type) + out.Address = in.Address + return nil + }, + func(in *NodeCondition, out *newer.NodeCondition, s conversion.Scope) error { + out.Type = newer.NodeConditionType(in.Type) + out.Status = newer.ConditionStatus(in.Status) + if err := s.Convert(&in.LastHeartbeatTime, &out.LastHeartbeatTime, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + return nil + }, + func(in *newer.NodeCondition, out *NodeCondition, s conversion.Scope) error { + out.Type = NodeConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + if err := s.Convert(&in.LastHeartbeatTime, &out.LastHeartbeatTime, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + return nil + }, + func(in *NodeList, out *newer.NodeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Node, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.NodeList, out *NodeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Node, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *NodeSpec, out *newer.NodeSpec, s conversion.Scope) error { + out.PodCIDR = in.PodCIDR + out.ExternalID = in.ExternalID + out.Unschedulable = in.Unschedulable + return nil + }, + func(in *newer.NodeSpec, out *NodeSpec, s conversion.Scope) error { + out.PodCIDR = in.PodCIDR + out.ExternalID = in.ExternalID + out.Unschedulable = in.Unschedulable + return nil + }, + func(in *NodeStatus, out *newer.NodeStatus, s conversion.Scope) error { + if in.Capacity != nil { + out.Capacity = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[newer.ResourceName(key)] = newVal + } + } + out.Phase = newer.NodePhase(in.Phase) + if in.Conditions != nil { + out.Conditions = make([]newer.NodeCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + if in.Addresses != nil { + out.Addresses = make([]newer.NodeAddress, len(in.Addresses)) + for i := range in.Addresses { + if err := s.Convert(&in.Addresses[i], &out.Addresses[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.NodeInfo, &out.NodeInfo, 0); err != nil { + return err + } + return nil + }, + func(in *newer.NodeStatus, out *NodeStatus, s conversion.Scope) error { + if in.Capacity != nil { + out.Capacity = make(map[ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[ResourceName(key)] = newVal + } + } + out.Phase = NodePhase(in.Phase) + if in.Conditions != nil { + out.Conditions = make([]NodeCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + if in.Addresses != nil { + out.Addresses = make([]NodeAddress, len(in.Addresses)) + for i := range in.Addresses { + if err := s.Convert(&in.Addresses[i], &out.Addresses[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.NodeInfo, &out.NodeInfo, 0); err != nil { + return err + } + return nil + }, + func(in *NodeSystemInfo, out *newer.NodeSystemInfo, s conversion.Scope) error { + out.MachineID = in.MachineID + out.SystemUUID = in.SystemUUID + out.BootID = in.BootID + out.KernelVersion = in.KernelVersion + out.OsImage = in.OsImage + out.ContainerRuntimeVersion = in.ContainerRuntimeVersion + out.KubeletVersion = in.KubeletVersion + out.KubeProxyVersion = in.KubeProxyVersion + return nil + }, + func(in *newer.NodeSystemInfo, out *NodeSystemInfo, s conversion.Scope) error { + out.MachineID = in.MachineID + out.SystemUUID = in.SystemUUID + out.BootID = in.BootID + out.KernelVersion = in.KernelVersion + out.OsImage = in.OsImage + out.ContainerRuntimeVersion = in.ContainerRuntimeVersion + out.KubeletVersion = in.KubeletVersion + out.KubeProxyVersion = in.KubeProxyVersion + return nil + }, + func(in *ObjectMeta, out *newer.ObjectMeta, s conversion.Scope) error { + out.Name = in.Name + out.GenerateName = in.GenerateName + out.Namespace = in.Namespace + out.SelfLink = in.SelfLink + out.UID = in.UID + out.ResourceVersion = in.ResourceVersion + if err := s.Convert(&in.CreationTimestamp, &out.CreationTimestamp, 0); err != nil { + return err + } + if err := s.Convert(&in.DeletionTimestamp, &out.DeletionTimestamp, 0); err != nil { + return err + } + if in.Labels != nil { + out.Labels = make(map[string]string) + for key, val := range in.Labels { + out.Labels[key] = val + } + } + if in.Annotations != nil { + out.Annotations = make(map[string]string) + for key, val := range in.Annotations { + out.Annotations[key] = val + } + } + return nil + }, + func(in *newer.ObjectMeta, out *ObjectMeta, s conversion.Scope) error { + out.Name = in.Name + out.GenerateName = in.GenerateName + out.Namespace = in.Namespace + out.SelfLink = in.SelfLink + out.UID = in.UID + out.ResourceVersion = in.ResourceVersion + if err := s.Convert(&in.CreationTimestamp, &out.CreationTimestamp, 0); err != nil { + return err + } + if err := s.Convert(&in.DeletionTimestamp, &out.DeletionTimestamp, 0); err != nil { + return err + } + if in.Labels != nil { + out.Labels = make(map[string]string) + for key, val := range in.Labels { + out.Labels[key] = val + } + } + if in.Annotations != nil { + out.Annotations = make(map[string]string) + for key, val := range in.Annotations { + out.Annotations[key] = val + } + } + return nil + }, + func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = in.UID + out.APIVersion = in.APIVersion + out.ResourceVersion = in.ResourceVersion + out.FieldPath = in.FieldPath + return nil + }, + func(in *newer.ObjectReference, out *ObjectReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = in.UID + out.APIVersion = in.APIVersion + out.ResourceVersion = in.ResourceVersion + out.FieldPath = in.FieldPath + return nil + }, + func(in *PersistentVolume, out *newer.PersistentVolume, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolume, out *PersistentVolume, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeClaim, out *newer.PersistentVolumeClaim, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolumeClaim, out *PersistentVolumeClaim, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeClaimList, out *newer.PersistentVolumeClaimList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.PersistentVolumeClaim, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.PersistentVolumeClaimList, out *PersistentVolumeClaimList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]PersistentVolumeClaim, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *PersistentVolumeClaimSpec, out *newer.PersistentVolumeClaimSpec, s conversion.Scope) error { + if in.AccessModes != nil { + out.AccessModes = make([]newer.AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolumeClaimSpec, out *PersistentVolumeClaimSpec, s conversion.Scope) error { + if in.AccessModes != nil { + out.AccessModes = make([]AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeClaimStatus, out *newer.PersistentVolumeClaimStatus, s conversion.Scope) error { + out.Phase = newer.PersistentVolumeClaimPhase(in.Phase) + if in.AccessModes != nil { + out.AccessModes = make([]newer.AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if in.Capacity != nil { + out.Capacity = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[newer.ResourceName(key)] = newVal + } + } + if err := s.Convert(&in.VolumeRef, &out.VolumeRef, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolumeClaimStatus, out *PersistentVolumeClaimStatus, s conversion.Scope) error { + out.Phase = PersistentVolumeClaimPhase(in.Phase) + if in.AccessModes != nil { + out.AccessModes = make([]AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if in.Capacity != nil { + out.Capacity = make(map[ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[ResourceName(key)] = newVal + } + } + if err := s.Convert(&in.VolumeRef, &out.VolumeRef, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeClaimVolumeSource, out *newer.PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + out.ClaimName = in.ClaimName + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *newer.PersistentVolumeClaimVolumeSource, out *PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + out.ClaimName = in.ClaimName + out.ReadOnly = in.ReadOnly + return nil + }, + func(in *PersistentVolumeList, out *newer.PersistentVolumeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.PersistentVolume, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.PersistentVolumeList, out *PersistentVolumeList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]PersistentVolume, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *PersistentVolumeSource, out *newer.PersistentVolumeSource, s conversion.Scope) error { + if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { + return err + } + if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { + return err + } + if err := s.Convert(&in.HostPath, &out.HostPath, 0); err != nil { + return err + } + if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolumeSource, out *PersistentVolumeSource, s conversion.Scope) error { + if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { + return err + } + if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { + return err + } + if err := s.Convert(&in.HostPath, &out.HostPath, 0); err != nil { + return err + } + if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeSpec, out *newer.PersistentVolumeSpec, s conversion.Scope) error { + if in.Capacity != nil { + out.Capacity = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[newer.ResourceName(key)] = newVal + } + } + if err := s.Convert(&in.PersistentVolumeSource, &out.PersistentVolumeSource, 0); err != nil { + return err + } + if in.AccessModes != nil { + out.AccessModes = make([]newer.AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.ClaimRef, &out.ClaimRef, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PersistentVolumeSpec, out *PersistentVolumeSpec, s conversion.Scope) error { + if in.Capacity != nil { + out.Capacity = make(map[ResourceName]resource.Quantity) + for key, val := range in.Capacity { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Capacity[ResourceName(key)] = newVal + } + } + if err := s.Convert(&in.PersistentVolumeSource, &out.PersistentVolumeSource, 0); err != nil { + return err + } + if in.AccessModes != nil { + out.AccessModes = make([]AccessModeType, len(in.AccessModes)) + for i := range in.AccessModes { + if err := s.Convert(&in.AccessModes[i], &out.AccessModes[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.ClaimRef, &out.ClaimRef, 0); err != nil { + return err + } + return nil + }, + func(in *PersistentVolumeStatus, out *newer.PersistentVolumeStatus, s conversion.Scope) error { + out.Phase = newer.PersistentVolumePhase(in.Phase) + return nil + }, + func(in *newer.PersistentVolumeStatus, out *PersistentVolumeStatus, s conversion.Scope) error { + out.Phase = PersistentVolumePhase(in.Phase) + return nil + }, + func(in *Pod, out *newer.Pod, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Pod, out *Pod, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *PodCondition, out *newer.PodCondition, s conversion.Scope) error { + out.Type = newer.PodConditionType(in.Type) + out.Status = newer.ConditionStatus(in.Status) + return nil + }, + func(in *newer.PodCondition, out *PodCondition, s conversion.Scope) error { + out.Type = PodConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + return nil + }, + func(in *PodExecOptions, out *newer.PodExecOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + out.Command = in.Command + return nil + }, + func(in *newer.PodExecOptions, out *PodExecOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + out.Command = in.Command + return nil + }, + func(in *PodList, out *newer.PodList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Pod, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.PodList, out *PodList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Pod, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *PodLogOptions, out *newer.PodLogOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Container = in.Container + out.Follow = in.Follow + return nil + }, + func(in *newer.PodLogOptions, out *PodLogOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Container = in.Container + out.Follow = in.Follow + return nil + }, + func(in *PodProxyOptions, out *newer.PodProxyOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Path = in.Path + return nil + }, + func(in *newer.PodProxyOptions, out *PodProxyOptions, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + out.Path = in.Path + return nil + }, + func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + if err := s.Convert(&in.ValueFrom, &out.ValueFrom, 0); err != nil { + return err + } + + return nil + }, + func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + if err := s.Convert(&in.ValueFrom, &out.ValueFrom, 0); err != nil { + return err + } + return nil + }, + func(in *PodSpec, out *newer.PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + out.Volumes = make([]newer.Volume, len(in.Volumes)) + for i := range in.Volumes { + if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { + return err + } + } + } + if in.Containers != nil { + out.Containers = make([]newer.Container, len(in.Containers)) + for i := range in.Containers { + if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { + return err + } + } + } + out.RestartPolicy = newer.RestartPolicy(in.RestartPolicy) + out.DNSPolicy = newer.DNSPolicy(in.DNSPolicy) + if in.NodeSelector != nil { + out.NodeSelector = make(map[string]string) + for key, val := range in.NodeSelector { + out.NodeSelector[key] = val + } + } + out.Host = in.Host + out.HostNetwork = in.HostNetwork + return nil + }, + func(in *newer.PodSpec, out *PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + out.Volumes = make([]Volume, len(in.Volumes)) + for i := range in.Volumes { + if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { + return err + } + } + } + if in.Containers != nil { + out.Containers = make([]Container, len(in.Containers)) + for i := range in.Containers { + if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { + return err + } + } + } + out.RestartPolicy = RestartPolicy(in.RestartPolicy) + out.DNSPolicy = DNSPolicy(in.DNSPolicy) + if in.NodeSelector != nil { + out.NodeSelector = make(map[string]string) + for key, val := range in.NodeSelector { + out.NodeSelector[key] = val + } + } + out.Host = in.Host + out.HostNetwork = in.HostNetwork + return nil + }, + func(in *PodStatus, out *newer.PodStatus, s conversion.Scope) error { + out.Phase = newer.PodPhase(in.Phase) + if in.Conditions != nil { + out.Conditions = make([]newer.PodCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + out.Message = in.Message + out.HostIP = in.HostIP + out.PodIP = in.PodIP + if in.ContainerStatuses != nil { + out.ContainerStatuses = make([]newer.ContainerStatus, len(in.ContainerStatuses)) + for i := range in.ContainerStatuses { + if err := s.Convert(&in.ContainerStatuses[i], &out.ContainerStatuses[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.PodStatus, out *PodStatus, s conversion.Scope) error { + out.Phase = PodPhase(in.Phase) + if in.Conditions != nil { + out.Conditions = make([]PodCondition, len(in.Conditions)) + for i := range in.Conditions { + if err := s.Convert(&in.Conditions[i], &out.Conditions[i], 0); err != nil { + return err + } + } + } + out.Message = in.Message + out.HostIP = in.HostIP + out.PodIP = in.PodIP + if in.ContainerStatuses != nil { + out.ContainerStatuses = make([]ContainerStatus, len(in.ContainerStatuses)) + for i := range in.ContainerStatuses { + if err := s.Convert(&in.ContainerStatuses[i], &out.ContainerStatuses[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *PodStatusResult, out *newer.PodStatusResult, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PodStatusResult, out *PodStatusResult, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *PodTemplate, out *newer.PodTemplate, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PodTemplate, out *PodTemplate, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil + }, + func(in *PodTemplateList, out *newer.PodTemplateList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.PodTemplate, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.PodTemplateList, out *PodTemplateList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]PodTemplate, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *PodTemplateSpec, out *newer.PodTemplateSpec, s conversion.Scope) error { + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PodTemplateSpec, out *PodTemplateSpec, s conversion.Scope) error { + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil + }, + func(in *Probe, out *newer.Probe, s conversion.Scope) error { + if err := s.Convert(&in.Handler, &out.Handler, 0); err != nil { + return err + } + out.InitialDelaySeconds = in.InitialDelaySeconds + out.TimeoutSeconds = in.TimeoutSeconds + return nil + }, + func(in *newer.Probe, out *Probe, s conversion.Scope) error { + if err := s.Convert(&in.Handler, &out.Handler, 0); err != nil { + return err + } + out.InitialDelaySeconds = in.InitialDelaySeconds + out.TimeoutSeconds = in.TimeoutSeconds + return nil + }, + func(in *ReplicationController, out *newer.ReplicationController, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ReplicationController, out *ReplicationController, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *ReplicationControllerList, out *newer.ReplicationControllerList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.ReplicationController, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.ReplicationControllerList, out *ReplicationControllerList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]ReplicationController, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ReplicationControllerSpec, out *newer.ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ReplicationControllerSpec, out *ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil + }, + func(in *ReplicationControllerStatus, out *newer.ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil + }, + func(in *newer.ReplicationControllerStatus, out *ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil + }, + func(in *ResourceQuota, out *newer.ResourceQuota, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ResourceQuota, out *ResourceQuota, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *ResourceQuotaList, out *newer.ResourceQuotaList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.ResourceQuota, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.ResourceQuotaList, out *ResourceQuotaList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]ResourceQuota, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ResourceQuotaSpec, out *newer.ResourceQuotaSpec, s conversion.Scope) error { + if in.Hard != nil { + out.Hard = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Hard { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Hard[newer.ResourceName(key)] = newVal + } + } + return nil + }, + func(in *newer.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error { + if in.Hard != nil { + out.Hard = make(map[ResourceName]resource.Quantity) + for key, val := range in.Hard { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Hard[ResourceName(key)] = newVal + } + } + return nil + }, + func(in *ResourceQuotaStatus, out *newer.ResourceQuotaStatus, s conversion.Scope) error { + if in.Hard != nil { + out.Hard = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Hard { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Hard[newer.ResourceName(key)] = newVal + } + } + if in.Used != nil { + out.Used = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Used { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Used[newer.ResourceName(key)] = newVal + } + } + return nil + }, + func(in *newer.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error { + if in.Hard != nil { + out.Hard = make(map[ResourceName]resource.Quantity) + for key, val := range in.Hard { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Hard[ResourceName(key)] = newVal + } + } + if in.Used != nil { + out.Used = make(map[ResourceName]resource.Quantity) + for key, val := range in.Used { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Used[ResourceName(key)] = newVal + } + } + return nil + }, + func(in *ResourceRequirements, out *newer.ResourceRequirements, s conversion.Scope) error { + if in.Limits != nil { + out.Limits = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Limits { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Limits[newer.ResourceName(key)] = newVal + } + } + if in.Requests != nil { + out.Requests = make(map[newer.ResourceName]resource.Quantity) + for key, val := range in.Requests { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Requests[newer.ResourceName(key)] = newVal + } + } + return nil + }, + func(in *newer.ResourceRequirements, out *ResourceRequirements, s conversion.Scope) error { + if in.Limits != nil { + out.Limits = make(map[ResourceName]resource.Quantity) + for key, val := range in.Limits { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Limits[ResourceName(key)] = newVal + } + } + if in.Requests != nil { + out.Requests = make(map[ResourceName]resource.Quantity) + for key, val := range in.Requests { + newVal := resource.Quantity{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Requests[ResourceName(key)] = newVal + } + } + return nil + }, + func(in *Secret, out *newer.Secret, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Data != nil { + out.Data = make(map[string][]uint8) + for key, val := range in.Data { + newVal := []uint8{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Data[key] = newVal + } + } + out.Type = newer.SecretType(in.Type) + return nil + }, + func(in *newer.Secret, out *Secret, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if in.Data != nil { + out.Data = make(map[string][]uint8) + for key, val := range in.Data { + newVal := []uint8{} + if err := s.Convert(&val, &newVal, 0); err != nil { + return err + } + out.Data[key] = newVal + } + } + out.Type = SecretType(in.Type) + return nil + }, + func(in *SecretList, out *newer.SecretList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Secret, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.SecretList, out *SecretList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Secret, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *SecretVolumeSource, out *newer.SecretVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + return nil + }, + func(in *newer.SecretVolumeSource, out *SecretVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + return nil + }, + func(in *Service, out *newer.Service, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Service, out *Service, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil + }, + func(in *ServiceList, out *newer.ServiceList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Service, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *newer.ServiceList, out *ServiceList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Service, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil + }, + func(in *ServicePort, out *newer.ServicePort, s conversion.Scope) error { + out.Name = in.Name + out.Protocol = newer.Protocol(in.Protocol) + out.Port = in.Port + if err := s.Convert(&in.TargetPort, &out.TargetPort, 0); err != nil { + return err + } + return nil + }, + func(in *newer.ServicePort, out *ServicePort, s conversion.Scope) error { + out.Name = in.Name + out.Protocol = Protocol(in.Protocol) + out.Port = in.Port + if err := s.Convert(&in.TargetPort, &out.TargetPort, 0); err != nil { + return err + } + return nil + }, + func(in *ServiceSpec, out *newer.ServiceSpec, s conversion.Scope) error { + if in.Ports != nil { + out.Ports = make([]newer.ServicePort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + out.PortalIP = in.PortalIP + out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer + if in.PublicIPs != nil { + out.PublicIPs = make([]string, len(in.PublicIPs)) + for i := range in.PublicIPs { + out.PublicIPs[i] = in.PublicIPs[i] + } + } + out.SessionAffinity = newer.AffinityType(in.SessionAffinity) + return nil + }, + func(in *newer.ServiceSpec, out *ServiceSpec, s conversion.Scope) error { + if in.Ports != nil { + out.Ports = make([]ServicePort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + out.PortalIP = in.PortalIP + out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer + if in.PublicIPs != nil { + out.PublicIPs = make([]string, len(in.PublicIPs)) + for i := range in.PublicIPs { + out.PublicIPs[i] = in.PublicIPs[i] + } + } + out.SessionAffinity = AffinityType(in.SessionAffinity) + return nil + }, + func(in *ServiceStatus, out *newer.ServiceStatus, s conversion.Scope) error { + return nil + }, + func(in *newer.ServiceStatus, out *ServiceStatus, s conversion.Scope) error { + return nil + }, + func(in *Status, out *newer.Status, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + out.Status = in.Status + out.Message = in.Message + out.Reason = newer.StatusReason(in.Reason) + if err := s.Convert(&in.Details, &out.Details, 0); err != nil { + return err + } + out.Code = in.Code + return nil + }, + func(in *newer.Status, out *Status, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + out.Status = in.Status + out.Message = in.Message + out.Reason = StatusReason(in.Reason) + if err := s.Convert(&in.Details, &out.Details, 0); err != nil { + return err + } + out.Code = in.Code + return nil + }, + func(in *StatusCause, out *newer.StatusCause, s conversion.Scope) error { + out.Type = newer.CauseType(in.Type) + out.Message = in.Message + out.Field = in.Field + return nil + }, + func(in *newer.StatusCause, out *StatusCause, s conversion.Scope) error { + out.Type = CauseType(in.Type) + out.Message = in.Message + out.Field = in.Field + return nil + }, + func(in *StatusDetails, out *newer.StatusDetails, s conversion.Scope) error { + out.ID = in.ID + out.Kind = in.Kind + if in.Causes != nil { + out.Causes = make([]newer.StatusCause, len(in.Causes)) + for i := range in.Causes { + if err := s.Convert(&in.Causes[i], &out.Causes[i], 0); err != nil { + return err + } + } + } + out.RetryAfterSeconds = in.RetryAfterSeconds + return nil + }, + func(in *newer.StatusDetails, out *StatusDetails, s conversion.Scope) error { + out.ID = in.ID + out.Kind = in.Kind + if in.Causes != nil { + out.Causes = make([]StatusCause, len(in.Causes)) + for i := range in.Causes { + if err := s.Convert(&in.Causes[i], &out.Causes[i], 0); err != nil { + return err + } + } + } + out.RetryAfterSeconds = in.RetryAfterSeconds + return nil + }, + func(in *TCPSocketAction, out *newer.TCPSocketAction, s conversion.Scope) error { + if err := s.Convert(&in.Port, &out.Port, 0); err != nil { + return err + } + return nil + }, + func(in *newer.TCPSocketAction, out *TCPSocketAction, s conversion.Scope) error { + if err := s.Convert(&in.Port, &out.Port, 0); err != nil { + return err + } + return nil + }, + func(in *TypeMeta, out *newer.TypeMeta, s conversion.Scope) error { + out.Kind = in.Kind + out.APIVersion = in.APIVersion + return nil + }, + func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error { + out.Kind = in.Kind + out.APIVersion = in.APIVersion + return nil + }, + func(in *Volume, out *newer.Volume, s conversion.Scope) error { + out.Name = in.Name + if err := s.Convert(&in.VolumeSource, &out.VolumeSource, 0); err != nil { + return err + } + return nil + }, + func(in *newer.Volume, out *Volume, s conversion.Scope) error { + out.Name = in.Name + if err := s.Convert(&in.VolumeSource, &out.VolumeSource, 0); err != nil { + return err + } + return nil + }, + func(in *VolumeMount, out *newer.VolumeMount, s conversion.Scope) error { + out.Name = in.Name + out.ReadOnly = in.ReadOnly + out.MountPath = in.MountPath + return nil + }, + func(in *newer.VolumeMount, out *VolumeMount, s conversion.Scope) error { + out.Name = in.Name + out.ReadOnly = in.ReadOnly + out.MountPath = in.MountPath + return nil + }, + func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error { + if err := s.Convert(&in.HostPath, &out.HostPath, 0); err != nil { + return err + } + if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { + return err + } + if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { + return err + } + if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { + return err + } + if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { + return err + } + if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { + return err + } + if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil { + return err + } + if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil { + return err + } + if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { + return err + } + if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil { + return err + } + return nil + }, + func(in *newer.VolumeSource, out *VolumeSource, s conversion.Scope) error { + if err := s.Convert(&in.HostPath, &out.HostPath, 0); err != nil { + return err + } + if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { + return err + } + if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { + return err + } + if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { + return err + } + if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { + return err + } + if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { + return err + } + if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil { + return err + } + if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil { + return err + } + if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { + return err + } + if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil { + return err + } + return nil + }, + ) + + // Add field conversion funcs. + err = newer.Scheme.AddFieldLabelConversionFunc("v1", "Pod", + func(label, value string) (string, string, error) { + switch label { + case "metadata.name", + "metadata.namespace", + "status.phase", + "spec.host": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } + err = newer.Scheme.AddFieldLabelConversionFunc("v1", "Node", + func(label, value string) (string, string, error) { + switch label { + case "metadata.name": + return label, value, nil + case "spec.unschedulable": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } + err = newer.Scheme.AddFieldLabelConversionFunc("v1", "ReplicationController", + func(label, value string) (string, string, error) { + switch label { + case "metadata.name", + "status.replicas": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } + err = newer.Scheme.AddFieldLabelConversionFunc("v1", "Event", + func(label, value string) (string, string, error) { + switch label { + case "involvedObject.kind", + "involvedObject.namespace", + "involvedObject.name", + "involvedObject.uid", + "involvedObject.apiVersion", + "involvedObject.resourceVersion", + "involvedObject.fieldPath", + "reason", + "source": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } + err = newer.Scheme.AddFieldLabelConversionFunc("v1", "Namespace", + func(label, value string) (string, string, error) { + switch label { + case "status.phase": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } +} diff --git a/pkg/api/v1/conversion_test.go b/pkg/api/v1/conversion_test.go new file mode 100644 index 00000000000..85077c1c44c --- /dev/null +++ b/pkg/api/v1/conversion_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1_test + +import ( + "testing" + + newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + current "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" +) + +func TestNodeConversion(t *testing.T) { + obj, err := current.Codec.Decode([]byte(`{"kind":"Minion","apiVersion":"v1"}`)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok := obj.(*newer.Node); !ok { + t.Errorf("unexpected type: %#v", obj) + } + + obj, err = current.Codec.Decode([]byte(`{"kind":"MinionList","apiVersion":"v1"}`)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok := obj.(*newer.NodeList); !ok { + t.Errorf("unexpected type: %#v", obj) + } + + obj = &newer.Node{} + if err := current.Codec.DecodeInto([]byte(`{"kind":"Minion","apiVersion":"v1"}`), obj); err != nil { + t.Fatalf("unexpected error: %v", err) + } +} diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go new file mode 100644 index 00000000000..262884e3b06 --- /dev/null +++ b/pkg/api/v1/defaults.go @@ -0,0 +1,158 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1 + +import ( + "strings" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" +) + +func init() { + api.Scheme.AddDefaultingFuncs( + func(obj *ReplicationController) { + var labels map[string]string + if obj.Spec.Template != nil { + labels = obj.Spec.Template.Labels + } + // TODO: support templates defined elsewhere when we support them in the API + if labels != nil { + if len(obj.Spec.Selector) == 0 { + obj.Spec.Selector = labels + } + if len(obj.Labels) == 0 { + obj.Labels = labels + } + } + }, + func(obj *Volume) { + if util.AllPtrFieldsNil(&obj.VolumeSource) { + obj.VolumeSource = VolumeSource{ + EmptyDir: &EmptyDirVolumeSource{}, + } + } + }, + func(obj *ContainerPort) { + if obj.Protocol == "" { + obj.Protocol = ProtocolTCP + } + }, + func(obj *Container) { + if obj.ImagePullPolicy == "" { + // TODO(dchen1107): Move ParseImageName code to pkg/util + parts := strings.Split(obj.Image, ":") + // Check image tag + if parts[len(parts)-1] == "latest" { + obj.ImagePullPolicy = PullAlways + } else { + obj.ImagePullPolicy = PullIfNotPresent + } + } + if obj.TerminationMessagePath == "" { + obj.TerminationMessagePath = TerminationMessagePathDefault + } + }, + func(obj *ServiceSpec) { + if obj.SessionAffinity == "" { + obj.SessionAffinity = AffinityTypeNone + } + for i := range obj.Ports { + sp := &obj.Ports[i] + if sp.Protocol == "" { + sp.Protocol = ProtocolTCP + } + if sp.TargetPort == util.NewIntOrStringFromInt(0) || sp.TargetPort == util.NewIntOrStringFromString("") { + sp.TargetPort = util.NewIntOrStringFromInt(sp.Port) + } + } + }, + func(obj *PodSpec) { + if obj.DNSPolicy == "" { + obj.DNSPolicy = DNSClusterFirst + } + if obj.RestartPolicy == "" { + obj.RestartPolicy = RestartPolicyAlways + } + if obj.HostNetwork { + defaultHostNetworkPorts(&obj.Containers) + } + }, + func(obj *Probe) { + if obj.TimeoutSeconds == 0 { + obj.TimeoutSeconds = 1 + } + }, + func(obj *Secret) { + if obj.Type == "" { + obj.Type = SecretTypeOpaque + } + }, + func(obj *PersistentVolume) { + if obj.Status.Phase == "" { + obj.Status.Phase = VolumePending + } + }, + func(obj *PersistentVolumeClaim) { + if obj.Status.Phase == "" { + obj.Status.Phase = ClaimPending + } + }, + func(obj *Endpoints) { + for i := range obj.Subsets { + ss := &obj.Subsets[i] + for i := range ss.Ports { + ep := &ss.Ports[i] + if ep.Protocol == "" { + ep.Protocol = ProtocolTCP + } + } + } + }, + func(obj *HTTPGetAction) { + if obj.Path == "" { + obj.Path = "/" + } + }, + func(obj *NamespaceStatus) { + if obj.Phase == "" { + obj.Phase = NamespaceActive + } + }, + func(obj *Node) { + if obj.Spec.ExternalID == "" { + obj.Spec.ExternalID = obj.Name + } + }, + func(obj *ObjectFieldSelector) { + if obj.APIVersion == "" { + obj.APIVersion = "v1" + } + }, + ) +} + +// With host networking default all container ports to host ports. +func defaultHostNetworkPorts(containers *[]Container) { + for i := range *containers { + for j := range (*containers)[i].Ports { + if (*containers)[i].Ports[j].HostPort == 0 { + (*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort + } + } + } +} diff --git a/pkg/api/v1/defaults_test.go b/pkg/api/v1/defaults_test.go new file mode 100644 index 00000000000..5b4d49e747b --- /dev/null +++ b/pkg/api/v1/defaults_test.go @@ -0,0 +1,351 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1_test + +import ( + "reflect" + "testing" + + newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + current "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" +) + +func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { + data, err := current.Codec.Encode(obj) + if err != nil { + t.Errorf("%v\n %#v", err, obj) + return nil + } + obj2, err := newer.Codec.Decode(data) + if err != nil { + t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj) + return nil + } + obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object) + err = newer.Scheme.Convert(obj2, obj3) + if err != nil { + t.Errorf("%v\nSource: %#v", err, obj2) + return nil + } + return obj3 +} + +func TestSetDefaultReplicationController(t *testing.T) { + tests := []struct { + rc *current.ReplicationController + expectLabels bool + expectSelector bool + }{ + { + rc: ¤t.ReplicationController{ + Spec: current.ReplicationControllerSpec{ + Template: ¤t.PodTemplateSpec{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + expectLabels: true, + expectSelector: true, + }, + { + rc: ¤t.ReplicationController{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "bar": "foo", + }, + }, + Spec: current.ReplicationControllerSpec{ + Template: ¤t.PodTemplateSpec{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + expectLabels: false, + expectSelector: true, + }, + { + rc: ¤t.ReplicationController{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "bar": "foo", + }, + }, + Spec: current.ReplicationControllerSpec{ + Selector: map[string]string{ + "some": "other", + }, + Template: ¤t.PodTemplateSpec{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + expectLabels: false, + expectSelector: false, + }, + { + rc: ¤t.ReplicationController{ + Spec: current.ReplicationControllerSpec{ + Selector: map[string]string{ + "some": "other", + }, + Template: ¤t.PodTemplateSpec{ + ObjectMeta: current.ObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + expectLabels: true, + expectSelector: false, + }, + } + + for _, test := range tests { + rc := test.rc + obj2 := roundTrip(t, runtime.Object(rc)) + rc2, ok := obj2.(*current.ReplicationController) + if !ok { + t.Errorf("unexpected object: %v", rc2) + t.FailNow() + } + if test.expectSelector != reflect.DeepEqual(rc2.Spec.Selector, rc2.Spec.Template.Labels) { + if test.expectSelector { + t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Spec.Selector) + } else { + t.Errorf("unexpected equality: %v", rc.Spec.Selector) + } + } + if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.Spec.Template.Labels) { + if test.expectLabels { + t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Labels) + } else { + t.Errorf("unexpected equality: %v", rc.Labels) + } + } + } +} + +func TestSetDefaultService(t *testing.T) { + svc := ¤t.Service{} + obj2 := roundTrip(t, runtime.Object(svc)) + svc2 := obj2.(*current.Service) + if svc2.Spec.SessionAffinity != current.AffinityTypeNone { + t.Errorf("Expected default sesseion affinity type:%s, got: %s", current.AffinityTypeNone, svc2.Spec.SessionAffinity) + } +} + +func TestSetDefaultSecret(t *testing.T) { + s := ¤t.Secret{} + obj2 := roundTrip(t, runtime.Object(s)) + s2 := obj2.(*current.Secret) + + if s2.Type != current.SecretTypeOpaque { + t.Errorf("Expected secret type %v, got %v", current.SecretTypeOpaque, s2.Type) + } +} + +func TestSetDefaultPersistentVolume(t *testing.T) { + pv := ¤t.PersistentVolume{} + obj2 := roundTrip(t, runtime.Object(pv)) + pv2 := obj2.(*current.PersistentVolume) + + if pv2.Status.Phase != current.VolumePending { + t.Errorf("Expected volume phase %v, got %v", current.VolumePending, pv2.Status.Phase) + } +} + +func TestSetDefaultPersistentVolumeClaim(t *testing.T) { + pvc := ¤t.PersistentVolumeClaim{} + obj2 := roundTrip(t, runtime.Object(pvc)) + pvc2 := obj2.(*current.PersistentVolumeClaim) + + if pvc2.Status.Phase != current.ClaimPending { + t.Errorf("Expected claim phase %v, got %v", current.ClaimPending, pvc2.Status.Phase) + } +} + +func TestSetDefaulEndpointsProtocol(t *testing.T) { + in := ¤t.Endpoints{Subsets: []current.EndpointSubset{ + {Ports: []current.EndpointPort{{}, {Protocol: "UDP"}, {}}}, + }} + obj := roundTrip(t, runtime.Object(in)) + out := obj.(*current.Endpoints) + + for i := range out.Subsets { + for j := range out.Subsets[i].Ports { + if in.Subsets[i].Ports[j].Protocol == "" { + if out.Subsets[i].Ports[j].Protocol != current.ProtocolTCP { + t.Errorf("Expected protocol %s, got %s", current.ProtocolTCP, out.Subsets[i].Ports[j].Protocol) + } + } else { + if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol { + t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol) + } + } + } + } +} + +func TestSetDefaulServiceTargetPort(t *testing.T) { + in := ¤t.Service{Spec: current.ServiceSpec{Ports: []current.ServicePort{{Port: 1234}}}} + obj := roundTrip(t, runtime.Object(in)) + out := obj.(*current.Service) + if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(1234) { + t.Errorf("Expected TargetPort to be defaulted, got %s", out.Spec.Ports[0].TargetPort) + } + + in = ¤t.Service{Spec: current.ServiceSpec{Ports: []current.ServicePort{{Port: 1234, TargetPort: util.NewIntOrStringFromInt(5678)}}}} + obj = roundTrip(t, runtime.Object(in)) + out = obj.(*current.Service) + if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(5678) { + t.Errorf("Expected TargetPort to be unchanged, got %s", out.Spec.Ports[0].TargetPort) + } +} + +func TestSetDefaultServicePort(t *testing.T) { + // Unchanged if set. + in := ¤t.Service{Spec: current.ServiceSpec{ + Ports: []current.ServicePort{ + {Protocol: "UDP", Port: 9376, TargetPort: util.NewIntOrStringFromString("p")}, + {Protocol: "UDP", Port: 8675, TargetPort: util.NewIntOrStringFromInt(309)}, + }, + }} + out := roundTrip(t, runtime.Object(in)).(*current.Service) + if out.Spec.Ports[0].Protocol != current.ProtocolUDP { + t.Errorf("Expected protocol %s, got %s", current.ProtocolUDP, out.Spec.Ports[0].Protocol) + } + if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromString("p") { + t.Errorf("Expected port %d, got %s", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort) + } + if out.Spec.Ports[1].Protocol != current.ProtocolUDP { + t.Errorf("Expected protocol %s, got %s", current.ProtocolUDP, out.Spec.Ports[1].Protocol) + } + if out.Spec.Ports[1].TargetPort != util.NewIntOrStringFromInt(309) { + t.Errorf("Expected port %d, got %s", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort) + } + + // Defaulted. + in = ¤t.Service{Spec: current.ServiceSpec{ + Ports: []current.ServicePort{ + {Protocol: "", Port: 9376, TargetPort: util.NewIntOrStringFromString("")}, + {Protocol: "", Port: 8675, TargetPort: util.NewIntOrStringFromInt(0)}, + }, + }} + out = roundTrip(t, runtime.Object(in)).(*current.Service) + if out.Spec.Ports[0].Protocol != current.ProtocolTCP { + t.Errorf("Expected protocol %s, got %s", current.ProtocolTCP, out.Spec.Ports[0].Protocol) + } + if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(in.Spec.Ports[0].Port) { + t.Errorf("Expected port %d, got %d", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort) + } + if out.Spec.Ports[1].Protocol != current.ProtocolTCP { + t.Errorf("Expected protocol %s, got %s", current.ProtocolTCP, out.Spec.Ports[1].Protocol) + } + if out.Spec.Ports[1].TargetPort != util.NewIntOrStringFromInt(in.Spec.Ports[1].Port) { + t.Errorf("Expected port %d, got %d", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort) + } +} + +func TestSetDefaultNamespace(t *testing.T) { + s := ¤t.Namespace{} + obj2 := roundTrip(t, runtime.Object(s)) + s2 := obj2.(*current.Namespace) + + if s2.Status.Phase != current.NamespaceActive { + t.Errorf("Expected phase %v, got %v", current.NamespaceActive, s2.Status.Phase) + } +} + +func TestSetDefaultPodSpecHostNetwork(t *testing.T) { + portNum := 8080 + s := current.PodSpec{} + s.HostNetwork = true + s.Containers = []current.Container{ + { + Ports: []current.ContainerPort{ + { + ContainerPort: portNum, + }, + }, + }, + } + pod := ¤t.Pod{ + Spec: s, + } + obj2 := roundTrip(t, runtime.Object(pod)) + pod2 := obj2.(*current.Pod) + s2 := pod2.Spec + + hostPortNum := s2.Containers[0].Ports[0].HostPort + if hostPortNum != portNum { + t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum) + } +} + +func TestSetDefaultNodeExternalID(t *testing.T) { + name := "node0" + n := ¤t.Node{} + n.Name = name + obj2 := roundTrip(t, runtime.Object(n)) + n2 := obj2.(*current.Node) + if n2.Spec.ExternalID != name { + t.Errorf("Expected default External ID: %s, got: %s", name, n2.Spec.ExternalID) + } +} + +func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { + s := current.PodSpec{ + Containers: []current.Container{ + { + Env: []current.EnvVar{ + { + ValueFrom: ¤t.EnvVarSource{ + FieldPath: ¤t.ObjectFieldSelector{}, + }, + }, + }, + }, + }, + } + pod := ¤t.Pod{ + Spec: s, + } + obj2 := roundTrip(t, runtime.Object(pod)) + pod2 := obj2.(*current.Pod) + s2 := pod2.Spec + + apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldPath.APIVersion + if apiVersion != "v1" { + t.Errorf("Expected default APIVersion v1, got: %v", apiVersion) + } +} diff --git a/pkg/api/v1/doc.go b/pkg/api/v1/doc.go new file mode 100644 index 00000000000..e8437aa8d74 --- /dev/null +++ b/pkg/api/v1/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1 is the v1 version of the API. +package v1 diff --git a/pkg/api/v1/register.go b/pkg/api/v1/register.go new file mode 100644 index 00000000000..35d616c5198 --- /dev/null +++ b/pkg/api/v1/register.go @@ -0,0 +1,108 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1 + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" +) + +// Codec encodes internal objects to the v1 scheme +var Codec = runtime.CodecFor(api.Scheme, "v1") + +func init() { + api.Scheme.AddKnownTypes("v1", + &Pod{}, + &PodList{}, + &PodStatusResult{}, + &PodTemplate{}, + &PodTemplateList{}, + &ReplicationController{}, + &ReplicationControllerList{}, + &Service{}, + &ServiceList{}, + &Endpoints{}, + &EndpointsList{}, + &Node{}, + &NodeList{}, + &Binding{}, + &Status{}, + &Event{}, + &EventList{}, + &List{}, + &LimitRange{}, + &LimitRangeList{}, + &ResourceQuota{}, + &ResourceQuotaList{}, + &Namespace{}, + &NamespaceList{}, + &Secret{}, + &SecretList{}, + &PersistentVolume{}, + &PersistentVolumeList{}, + &PersistentVolumeClaim{}, + &PersistentVolumeClaimList{}, + &DeleteOptions{}, + &ListOptions{}, + &PodLogOptions{}, + &PodExecOptions{}, + &PodProxyOptions{}, + &ComponentStatus{}, + &ComponentStatusList{}, + ) + // Legacy names are supported + api.Scheme.AddKnownTypeWithName("v1", "Minion", &Node{}) + api.Scheme.AddKnownTypeWithName("v1", "MinionList", &NodeList{}) +} + +func (*Pod) IsAnAPIObject() {} +func (*PodList) IsAnAPIObject() {} +func (*PodStatusResult) IsAnAPIObject() {} +func (*PodTemplate) IsAnAPIObject() {} +func (*PodTemplateList) IsAnAPIObject() {} +func (*ReplicationController) IsAnAPIObject() {} +func (*ReplicationControllerList) IsAnAPIObject() {} +func (*Service) IsAnAPIObject() {} +func (*ServiceList) IsAnAPIObject() {} +func (*Endpoints) IsAnAPIObject() {} +func (*EndpointsList) IsAnAPIObject() {} +func (*Node) IsAnAPIObject() {} +func (*NodeList) IsAnAPIObject() {} +func (*Binding) IsAnAPIObject() {} +func (*Status) IsAnAPIObject() {} +func (*Event) IsAnAPIObject() {} +func (*EventList) IsAnAPIObject() {} +func (*List) IsAnAPIObject() {} +func (*LimitRange) IsAnAPIObject() {} +func (*LimitRangeList) IsAnAPIObject() {} +func (*ResourceQuota) IsAnAPIObject() {} +func (*ResourceQuotaList) IsAnAPIObject() {} +func (*Namespace) IsAnAPIObject() {} +func (*NamespaceList) IsAnAPIObject() {} +func (*Secret) IsAnAPIObject() {} +func (*SecretList) IsAnAPIObject() {} +func (*PersistentVolume) IsAnAPIObject() {} +func (*PersistentVolumeList) IsAnAPIObject() {} +func (*PersistentVolumeClaim) IsAnAPIObject() {} +func (*PersistentVolumeClaimList) IsAnAPIObject() {} +func (*DeleteOptions) IsAnAPIObject() {} +func (*ListOptions) IsAnAPIObject() {} +func (*PodLogOptions) IsAnAPIObject() {} +func (*PodExecOptions) IsAnAPIObject() {} +func (*PodProxyOptions) IsAnAPIObject() {} +func (*ComponentStatus) IsAnAPIObject() {} +func (*ComponentStatusList) IsAnAPIObject() {} diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go new file mode 100644 index 00000000000..e162cbf1a07 --- /dev/null +++ b/pkg/api/v1/types.go @@ -0,0 +1,1727 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 v1 + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/GoogleCloudPlatform/kubernetes/pkg/types" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" +) + +// Common string formats +// --------------------- +// Many fields in this API have formatting requirements. The commonly used +// formats are defined here. +// +// C_IDENTIFIER: This is a string that conforms to the definition of an "identifier" +// in the C language. This is captured by the following regex: +// [A-Za-z_][A-Za-z0-9_]* +// This defines the format, but not the length restriction, which should be +// specified at the definition of any field of this type. +// +// DNS_LABEL: This is a string, no more than 63 characters long, that conforms +// to the definition of a "label" in RFCs 1035 and 1123. This is captured +// by the following regex: +// [a-z0-9]([-a-z0-9]*[a-z0-9])? +// +// DNS_SUBDOMAIN: This is a string, no more than 253 characters long, that conforms +// to the definition of a "subdomain" in RFCs 1035 and 1123. This is captured +// by the following regex: +// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* +// or more simply: +// DNS_LABEL(\.DNS_LABEL)* + +// TypeMeta describes an individual object in an API response or request +// with strings representing the type of the object and its API schema version. +// Structures that are versioned or persisted should inline TypeMeta. +type TypeMeta struct { + // Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + Kind string `json:"kind,omitempty" description:"kind of object, in CamelCase; cannot be updated"` + + // APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + APIVersion string `json:"apiVersion,omitempty" description:"version of the schema the object should have"` +} + +// ListMeta describes metadata that synthetic resources must have, including lists and +// various status objects. +type ListMeta struct { + // SelfLink is a URL representing this object. + SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"` + + // An opaque value that represents the version of this response for use with optimistic + // concurrency and change monitoring endpoints. Clients must treat these values as opaque + // and values may only be valid for a particular resource or set of resources. Only servers + // will generate resource versions. + ResourceVersion string `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; populated by the system, read-only; value must be treated as opaque by clients and passed unmodified back to the server: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"` +} + +// ObjectMeta is metadata that all persisted resources must have, which includes all objects +// users must create. +type ObjectMeta struct { + // Name is unique within a namespace. Name is required when creating resources, although + // some resources may allow a client to request the generation of an appropriate name + // automatically. Name is primarily intended for creation idempotence and configuration + // definition. + Name string `json:"name,omitempty" description:"string that identifies an object. Must be unique within a namespace; cannot be updated"` + + // GenerateName indicates that the name should be made unique by the server prior to persisting + // it. A non-empty value for the field indicates the name will be made unique (and the name + // returned to the client will be different than the name passed). The value of this field will + // be combined with a unique suffix on the server if the Name field has not been provided. + // The provided value must be valid within the rules for Name, and may be truncated by the length + // of the suffix required to make the value unique on the server. + // + // If this field is specified, and Name is not present, the server will NOT return a 409 if the + // generated name exists - instead, it will either return 201 Created or 500 with Reason + // ServerTimeout indicating a unique name could not be found in the time allotted, and the client + // should retry (optionally after the time indicated in the Retry-After header). + GenerateName string `json:"generateName,omitempty" description:"an optional prefix to use to generate a unique name; has the same validation rules as name; optional, and is applied only name if is not specified"` + + // Namespace defines the space within which name must be unique. An empty namespace is + // equivalent to the "default" namespace, but "default" is the canonical representation. + // Not all objects are required to be scoped to a namespace - the value of this field for + // those objects will be empty. + Namespace string `json:"namespace,omitempty" description:"namespace of the object; cannot be updated"` + + // SelfLink is a URL representing this object. + SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"` + + // UID is the unique in time and space value for this object. It is typically generated by + // the server on successful creation of a resource and is not allowed to change on PUT + // operations. + UID types.UID `json:"uid,omitempty" description:"unique UUID across space and time; populated by the system; read-only"` + + // An opaque value that represents the version of this resource. May be used for optimistic + // concurrency, change detection, and the watch operation on a resource or set of resources. + // Clients must treat these values as opaque and values may only be valid for a particular + // resource or set of resources. Only servers will generate resource versions. + ResourceVersion string `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; populated by the system, read-only; value must be treated as opaque by clients and passed unmodified back to the server: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"` + + // CreationTimestamp is a timestamp representing the server time when this object was + // created. It is not guaranteed to be set in happens-before order across separate operations. + // Clients may not set this value. It is represented in RFC3339 form and is in UTC. + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" description:"RFC 3339 date and time at which the object was created; populated by the system, read-only; null for lists"` + + // DeletionTimestamp is the time after which this resource will be deleted. This + // field is set by the server when a graceful deletion is requested by the user, and is not + // directly settable by a client. The resource will be deleted (no longer visible from + // resource lists, and not reachable by name) after the time in this field. Once set, this + // value may not be unset or be set further into the future, although it may be shortened + // or the resource may be deleted prior to this time. For example, a user may request that + // a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination + // signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet + // will send a hard termination signal to the container. + DeletionTimestamp *util.Time `json:"deletionTimestamp,omitempty" description:"RFC 3339 date and time at which the object will be deleted; populated by the system when a graceful deletion is requested, read-only; if not set, graceful deletion of the object has not been requested"` + + // Labels are key value pairs that may be used to scope and select individual resources. + // TODO: replace map[string]string with labels.LabelSet type + Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize objects; may match selectors of replication controllers and services"` + + // Annotations are unstructured key value data stored with a resource that may be set by + // external tooling. They are not queryable and should be preserved when modifying + // objects. + Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about objects"` +} + +const ( + // NamespaceDefault means the object is in the default namespace which is applied when not specified by clients + NamespaceDefault string = "default" + // NamespaceAll is the default argument to specify on a context when you want to list or filter resources across all namespaces + NamespaceAll string = "" +) + +// +//// ContainerManifest corresponds to the Container Manifest format, documented at: +//// https://developers.google.com/compute/docs/containers/container_vms#container_manifest +//// This is used as the representation of Kubernetes workloads. +//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd +//// directly. +//type ContainerManifest struct { +// // Required: This must be a supported version string, such as "v1beta1". +// Version string `json:"version"` +// // Required: This must be a DNS_SUBDOMAIN. +// // TODO: ID on Manifest is deprecated and will be removed in the future. +// ID string `json:"id"` +// // TODO: UUID on Manifest is deprecated in the future once we are done +// // with the API refactoring. It is required for now to determine the instance +// // of a Pod. +// UUID types.UID `json:"uuid,omitempty"` +// Volumes []Volume `json:"volumes"` +// Containers []Container `json:"containers"` +// RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"` +//} +// +//// ContainerManifestList is used to communicate container manifests to kubelet. +//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd +//// directly. +//type ContainerManifestList struct { +// TypeMeta `json:",inline"` +// // ID is the legacy field representing Name +// ID string `json:"id,omitempty"` +// +// Items []ContainerManifest `json:"items,omitempty"` +//} + +// Volume represents a named volume in a pod that may be accessed by any containers in the pod. +type Volume struct { + // Required: This must be a DNS_LABEL. Each volume in a pod must have + // a unique name. + Name string `json:"name" description:"volume name; must be a DNS_LABEL and unique within the pod"` + // Source represents the location and type of a volume to mount. + // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. + // This implied behavior is deprecated and will be removed in a future version. + VolumeSource `json:",inline,omitempty"` +} + +// VolumeSource represents the source location of a volume to mount. +// Only one of its members may be specified. +type VolumeSource struct { + // HostPath represents a pre-existing file or directory on the host + // machine that is directly exposed to the container. This is generally + // used for system agents or other privileged things that are allowed + // to see the host machine. Most containers will NOT need this. + // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + // mount host directories as read/write. + HostPath *HostPathVolumeSource `json:"hostPath" description:"pre-existing host file or directory; generally for privileged system daemons or other agents tied to the host"` + // EmptyDir represents a temporary directory that shares a pod's lifetime. + EmptyDir *EmptyDirVolumeSource `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"` + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"gcePersistentDisk" description:"GCE disk resource attached to the host machine on demand"` + // AWSElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + AWSElasticBlockStore *AWSElasticBlockStoreVolumeSource `json:"awsElasticBlockStore" description:"AWS disk resource attached to the host machine on demand"` + // GitRepo represents a git repository at a particular revision. + GitRepo *GitRepoVolumeSource `json:"gitRepo" description:"git repository at a particular revision"` + // Secret represents a secret that should populate this volume. + Secret *SecretVolumeSource `json:"secret" description:"secret to populate volume"` + // NFS represents an NFS mount on the host that shares a pod's lifetime + NFS *NFSVolumeSource `json:"nfs" description:"NFS volume that will be mounted in the host machine"` + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi" description:"iSCSI disk attached to host machine on demand"` + // Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime + Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume that will be mounted on the host machine "` + // PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace + PersistentVolumeClaimVolumeSource *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" description:"a reference to a PersistentVolumeClaim in the same namespace"` +} + +type PersistentVolumeClaimVolumeSource struct { + // ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume + ClaimName string `json:"claimName,omitempty" description:"the name of the claim in the same namespace to be mounted as a volume"` + // Optional: Defaults to false (read/write). ReadOnly here + // will force the ReadOnly setting in VolumeMounts + ReadOnly bool `json:"readOnly,omitempty" description:"mount volume as read-only when true; default false"` +} + +// Similar to VolumeSource but meant for the administrator who creates PVs. +// Exactly one of its members must be set. +type PersistentVolumeSource struct { + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"gcePersistentDisk" description:"GCE disk resource provisioned by an admin"` + // AWSElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + AWSElasticBlockStore *AWSElasticBlockStoreVolumeSource `json:"awsElasticBlockStore" description:"AWS disk resource provisioned by an admin"` + // HostPath represents a directory on the host. + // This is useful for development and testing only. + // on-host storage is not supported in any way. + HostPath *HostPathVolumeSource `json:"hostPath" description:"a HostPath provisioned by a developer or tester; for develment use only"` + // Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod + Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume resource provisioned by an admin"` +} + +type PersistentVolume struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` + + //Spec defines a persistent volume owned by the cluster + Spec PersistentVolumeSpec `json:"spec,omitempty" description:"specification of a persistent volume as provisioned by an administrator"` + + // Status represents the current information about persistent volume. + Status PersistentVolumeStatus `json:"status,omitempty" description:"current status of a persistent volume; populated by the system, read-only"` +} + +type PersistentVolumeSpec struct { + // Resources represents the actual resources of the volume + Capacity ResourceList `json:"capacity,omitempty" description:"a description of the persistent volume's resources and capacity"` + // Source represents the location and type of a volume to mount. + PersistentVolumeSource `json:",inline" description:"the actual volume backing the persistent volume"` + // AccessModes contains all ways the volume can be mounted + AccessModes []AccessModeType `json:"accessModes,omitempty" description:"all ways the volume can be mounted"` + // holds the binding reference to a PersistentVolumeClaim + ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"the binding reference to a persistent volume claim"` +} + +type PersistentVolumeStatus struct { + // Phase indicates if a volume is available, bound to a claim, or released by a claim + Phase PersistentVolumePhase `json:"phase,omitempty" description:"the current phase of a persistent volume"` +} + +type PersistentVolumeList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` + Items []PersistentVolume `json:"items,omitempty" description:"list of persistent volumes"` +} + +// PersistentVolumeClaim is a user's request for and claim to a persistent volume +type PersistentVolumeClaim struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the volume requested by a pod author + Spec PersistentVolumeClaimSpec `json:"spec,omitempty" description: "the desired characteristics of a volume"` + + // Status represents the current information about a claim + Status PersistentVolumeClaimStatus `json:"status,omitempty" description:"the current status of a persistent volume claim; read-only"` +} + +type PersistentVolumeClaimList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty"` + Items []PersistentVolumeClaim `json:"items,omitempty" description: "a list of persistent volume claims"` +} + +// PersistentVolumeClaimSpec describes the common attributes of storage devices +// and allows a Source for provider-specific attributes +type PersistentVolumeClaimSpec struct { + // Contains the types of access modes required + AccessModes []AccessModeType `json:"accessModes,omitempty" description:"the desired access modes the volume should have"` + // Resources represents the minimum resources required + Resources ResourceRequirements `json:"resources,omitempty" description:"the desired resources the volume should have"` +} + +type PersistentVolumeClaimStatus struct { + // Phase represents the current phase of PersistentVolumeClaim + Phase PersistentVolumeClaimPhase `json:"phase,omitempty" description:"the current phase of the claim"` + // AccessModes contains all ways the volume backing the PVC can be mounted + AccessModes []AccessModeType `json:"accessModes,omitempty" description:"the actual access modes the volume has"` + // Represents the actual resources of the underlying volume + Capacity ResourceList `json:"capacity,omitempty" description:"the actual resources the volume has"` + // VolumeRef is a reference to the PersistentVolume bound to the PersistentVolumeClaim + VolumeRef *ObjectReference `json:"volumeRef,omitempty" description:"a reference to the backing persistent volume, when bound"` +} + +type AccessModeType string + +const ( + // can be mounted read/write mode to exactly 1 host + ReadWriteOnce AccessModeType = "ReadWriteOnce" + // can be mounted in read-only mode to many hosts + ReadOnlyMany AccessModeType = "ReadOnlyMany" + // can be mounted in read/write mode to many hosts + ReadWriteMany AccessModeType = "ReadWriteMany" +) + +type PersistentVolumePhase string + +const ( + // used for PersistentVolumes that are not available + VolumePending PersistentVolumePhase = "Pending" + // used for PersistentVolumes that are not yet bound + VolumeAvailable PersistentVolumePhase = "Available" + // used for PersistentVolumes that are bound + VolumeBound PersistentVolumePhase = "Bound" + // used for PersistentVolumes where the bound PersistentVolumeClaim was deleted + // released volumes must be recycled before becoming available again + VolumeReleased PersistentVolumePhase = "Released" +) + +type PersistentVolumeClaimPhase string + +const ( + // used for PersistentVolumeClaims that are not yet bound + ClaimPending PersistentVolumeClaimPhase = "Pending" + // used for PersistentVolumeClaims that are bound + ClaimBound PersistentVolumeClaimPhase = "Bound" +) + +// HostPathVolumeSource represents bare host directory volume. +type HostPathVolumeSource struct { + Path string `json:"path" description:"path of the directory on the host"` +} + +type EmptyDirVolumeSource struct { + // Optional: what type of storage medium should back this directory. + // The default is "" which means to use the node's default medium. + Medium StorageType `json:"medium" description:"type of storage used to back the volume; must be an empty string (default) or Memory"` +} + +// GlusterfsVolumeSource represents a Glusterfs Mount that lasts the lifetime of a pod +type GlusterfsVolumeSource struct { + // Required: EndpointsName is the endpoint name that details Glusterfs topology + EndpointsName string `json:"endpoints" description:"gluster hosts endpoints name"` + + // Required: Path is the Glusterfs volume path + Path string `json:"path" description:"path to gluster volume"` + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the Glusterfs volume to be mounted with read-only permissions + ReadOnly bool `json:"readOnly,omitempty" description:"glusterfs volume to be mounted with read-only permissions"` +} + +// StorageType defines ways that storage can be allocated to a volume. +type StorageType string + +const ( + StorageTypeDefault StorageType = "" // use whatever the default is for the node + StorageTypeMemory StorageType = "Memory" // use memory (tmpfs) +) + +// Protocol defines network protocols supported for things like conatiner ports. +type Protocol string + +const ( + // ProtocolTCP is the TCP protocol. + ProtocolTCP Protocol = "TCP" + // ProtocolUDP is the UDP protocol. + ProtocolUDP Protocol = "UDP" +) + +// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine. +// +// A GCE PD must exist and be formatted before mounting to a container. +// The disk must also be in the same GCE project and zone as the kubelet. +// A GCE PD can only be mounted as read/write once. +type GCEPersistentDiskVolumeSource struct { + // Unique name of the PD resource. Used to identify the disk in GCE + PDName string `json:"pdName" description:"unique name of the PD resource in GCE"` + // Required: Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs" + // TODO: how do we prevent errors in the filesystem from compromising the machine + FSType string `json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` + // Optional: Partition on the disk to mount. + // If omitted, kubelet will attempt to mount the device name. + // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty. + Partition int `json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` +} + +// AWSElasticBlockStoreVolumeSource represents a Persistent Disk resource in AWS. +// +// An AWS PD must exist and be formatted before mounting to a container. +// The disk must also be in the same AWS zone as the kubelet. +// A AWS PD can only be mounted on a single machine. +type AWSElasticBlockStoreVolumeSource struct { + // Unique id of the PD resource. Used to identify the disk in AWS + VolumeID string `json:"volumeID" description:"unique id of the PD resource in AWS"` + // Required: Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs" + // TODO: how do we prevent errors in the filesystem from compromising the machine + // TODO: why omitempty if required? + FSType string `json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` + // Optional: Partition on the disk to mount. + // If omitted, kubelet will attempt to mount the device name. + // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field 0 or empty. + Partition int `json:"partition,omitempty" description:"partition on the disk to mount (e.g., '1' for /dev/sda1); if omitted the plain device name (e.g., /dev/sda) will be mounted"` + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` +} + +// GitRepoVolumeSource represents a volume that is pulled from git when the pod is created. +type GitRepoVolumeSource struct { + // Repository URL + Repository string `json:"repository" description:"repository URL"` + // Commit hash, this is optional + Revision string `json:"revision" description:"commit hash for the specified revision"` +} + +// SecretVolumeSource adapts a Secret into a VolumeSource +// +// http://docs.k8s.io/design/secrets.md +type SecretVolumeSource struct { + // Name of the secret in the pod's namespace to use + SecretName string `json:"secretName" description:"secretName is the name of a secret in the pod's namespace"` +} + +// NFSVolumeSource represents an NFS mount that lasts the lifetime of a pod +type NFSVolumeSource struct { + // Server is the hostname or IP address of the NFS server + Server string `json:"server" description:"the hostname or IP address of the NFS server"` + + // Path is the exported NFS share + Path string `json:"path" description:"the path that is exported by the NFS server"` + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the NFS export to be mounted with read-only permissions + ReadOnly bool `json:"readOnly,omitempty" description:"forces the NFS export to be mounted with read-only permissions"` +} + +// A ISCSI Disk can only be mounted as read/write once. +type ISCSIVolumeSource struct { + // Required: iSCSI target portal + // the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260) + TargetPortal string `json:"targetPortal,omitempty" description:"iSCSI target portal"` + // Required: target iSCSI Qualified Name + IQN string `json:"iqn,omitempty" description:"iSCSI Qualified Name"` + // Required: iSCSI target lun number + Lun int `json:"lun,omitempty" description:"iscsi target lun number"` + // Required: Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs" + // TODO: how do we prevent errors in the filesystem from compromising the machine + FSType string `json:"fsType,omitempty" description:"file system type to mount, such as ext4, xfs, ntfs"` + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"` +} + +// ContainerPort represents a network port in a single container. +type ContainerPort struct { + // Optional: If specified, this must be a DNS_LABEL. Each named port + // in a pod must have a unique name. + Name string `json:"name,omitempty" description:"name for the port that can be referred to by services; must be a DNS_LABEL and unique without the pod"` + // Optional: If specified, this must be a valid port number, 0 < x < 65536. + // If HostNetwork is specified, this must match ContainerPort. + HostPort int `json:"hostPort,omitempty" description:"number of port to expose on the host; most containers do not need this"` + // Required: This must be a valid port number, 0 < x < 65536. + ContainerPort int `json:"containerPort" description:"number of port to expose on the pod's IP address"` + // Optional: Defaults to "TCP". + Protocol Protocol `json:"protocol,omitempty" description:"protocol for port; must be UDP or TCP; TCP if unspecified"` + // Optional: What host IP to bind the external port to. + HostIP string `json:"hostIP,omitempty" description:"host IP to bind the port to"` +} + +// VolumeMount describes a mounting of a Volume within a container. +type VolumeMount struct { + // Required: This must match the Name of a Volume [above]. + Name string `json:"name" description:"name of the volume to mount"` + // Optional: Defaults to false (read-write). + ReadOnly bool `json:"readOnly,omitempty" description:"mounted read-only if true, read-write otherwise (false or unspecified)"` + // Required. + MountPath string `json:"mountPath" description:"path within the container at which the volume should be mounted"` +} + +// EnvVar represents an environment variable present in a Container. +type EnvVar struct { + // Required: This must be a C_IDENTIFIER. + Name string `json:"name" description:"name of the environment variable; must be a C_IDENTIFIER"` + // Optional: defaults to "". + Value string `json:"value,omitempty" description:"value of the environment variable; defaults to empty string"` + // Optional: specify a source the value of this var should come from. + ValueFrom *EnvVarSource `json:"valueFrom,omitempty" description:"source for the environment variable's value; cannot be used if value is not empty"` +} + +// EnvVarSource represents a source for the value of an EnvVar. +// Only one of its members may be specified. +type EnvVarSource struct { + // Selects a field of the pod; only name and namespace are supported. + FieldPath *ObjectFieldSelector `json:"fieldPath,omitempty" description:"selects a field of the pod; only name and namespace are supported"` +} + +// ObjectFieldSelector selects an APIVersioned field of an object. +type ObjectFieldSelector struct { + // The API version the FieldPath is written in terms of. + APIVersion string `json:"apiVersion,omitempty" description="The API version that FieldPath is written in terms of"` + // The path of the field to select in the specified API version + FieldPath string `json:"fieldPath,omitempty" description="The path of the field to select in the specified API version"` +} + +// HTTPGetAction describes an action based on HTTP Get requests. +type HTTPGetAction struct { + // Optional: Path to access on the HTTP server. + Path string `json:"path,omitempty" description:"path to access on the HTTP server"` + // Required: Name or number of the port to access on the container. + Port util.IntOrString `json:"port,omitempty" description:"number or name of the port to access on the container"` + // Optional: Host name to connect to, defaults to the pod IP. + Host string `json:"host,omitempty" description:"hostname to connect to; defaults to pod IP"` +} + +// TCPSocketAction describes an action based on opening a socket +type TCPSocketAction struct { + // Required: Port to connect to. + Port util.IntOrString `json:"port,omitempty" description:"number of name of the port to access on the container"` +} + +// ExecAction describes a "run in container" action. +type ExecAction struct { + // Command is the command line to execute inside the container, the working directory for the + // command is root ('/') in the container's filesystem. The command is simply exec'd, it is + // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + // a shell, you need to explicitly call out to that shell. + Command []string `json:"command,omitempty" description:"command line to execute inside the container; working directory for the command is root ('/') in the container's file system; the command is exec'd, not run inside a shell; exit status of 0 is treated as live/healthy and non-zero is unhealthy"` +} + +// Probe describes a liveness probe to be examined to the container. +type Probe struct { + // The action taken to determine the health of a container + Handler `json:",inline"` + // Length of time before health checking is activated. In seconds. + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty" description:"number of seconds after the container has started before liveness probes are initiated"` + // Length of time before health checking times out. In seconds. + TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" description:"number of seconds after which liveness probes timeout; defaults to 1 second"` +} + +// PullPolicy describes a policy for if/when to pull a container image +type PullPolicy string + +const ( + // PullAlways means that kubelet always attempts to pull the latest image. Container will fail If the pull fails. + PullAlways PullPolicy = "Always" + // PullNever means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present + PullNever PullPolicy = "Never" + // PullIfNotPresent means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails. + PullIfNotPresent PullPolicy = "IfNotPresent" +) + +// CapabilityType represent POSIX capabilities type +type CapabilityType string + +// Capabilities represent POSIX capabilities that can be added or removed to a running container. +type Capabilities struct { + // Added capabilities + Add []CapabilityType `json:"add,omitempty" description:"added capabilities"` + // Removed capabilities + Drop []CapabilityType `json:"drop,omitempty" description:"droped capabilities"` +} + +// ResourceRequirements describes the compute resource requirements. +type ResourceRequirements struct { + // Limits describes the maximum amount of compute resources required. + Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"` + // Requests describes the minimum amount of compute resources required. + Requests ResourceList `json:"requests,omitempty" description:"Minimum amount of resources requested"` +} + +const ( + // TerminationMessagePathDefault means the default path to capture the application termination message running in a container + TerminationMessagePathDefault string = "/dev/termination-log" +) + +// Container represents a single container that is expected to be run on the host. +type Container struct { + // Required: This must be a DNS_LABEL. Each container in a pod must + // have a unique name. + Name string `json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod; cannot be updated"` + // Required. + Image string `json:"image" description:"Docker image name"` + // Optional: The docker image's entrypoint is used if this is not provided; cannot be updated. + Command []string `json:"command,omitempty" description:"entrypoint array; not executed within a shell; the docker image's entrypoint is used if this is not provided; cannot be updated"` + // Optional: The docker image's cmd is used if this is not provided; cannot be updated. + Args []string `json:"args,omitempty" description:"command array; the docker image's cmd is used if this is not provided; arguments to the entrypoint; cannot be updated"` + // Optional: Defaults to Docker's default. + WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default; cannot be updated"` + Ports []ContainerPort `json:"ports,omitempty" description:"list of ports to expose from the container; cannot be updated" patchStrategy:"merge" patchMergeKey:"containerPort"` + Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container; cannot be updated" patchStrategy:"merge" patchMergeKey:"name"` + Resources ResourceRequirements `json:"resources,omitempty" description:"Compute Resources required by this container; cannot be updated"` + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesyste; cannot be updated" patchStrategy:"merge" patchMergeKey:"name"` + LivenessProbe *Probe `json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails; cannot be updated"` + ReadinessProbe *Probe `json:"readinessProbe,omitempty" description:"periodic probe of container service readiness; container will be removed from service endpoints if the probe fails; cannot be updated"` + Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events; cannot be updated"` + // Optional: Defaults to /dev/termination-log + TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated"` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated"` + // Optional: Policy for pulling images for this container + ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise; cannot be updated"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated"` +} + +// Handler defines a specific action that should be taken +// TODO: pass structured data to these actions, and document that data here. +type Handler struct { + // One and only one of the following should be specified. + // Exec specifies the action to take. + Exec *ExecAction `json:"exec,omitempty" description:"exec-based handler"` + // HTTPGet specifies the http request to perform. + HTTPGet *HTTPGetAction `json:"httpGet,omitempty" description:"HTTP-based handler"` + // TCPSocket specifies an action involving a TCP port. + // TODO: implement a realistic TCP lifecycle hook + TCPSocket *TCPSocketAction `json:"tcpSocket,omitempty" description:"TCP-based handler; TCP hooks not yet supported"` +} + +// Lifecycle describes actions that the management system should take in response to container lifecycle +// events. For the PostStart and PreStop lifecycle handlers, management of the container blocks +// until the action is complete, unless the container process fails, in which case the handler is aborted. +type Lifecycle struct { + // PostStart is called immediately after a container is created. If the handler fails, the container + // is terminated and restarted. + PostStart *Handler `json:"postStart,omitempty" description:"called immediately after a container is started; if the handler fails, the container is terminated and restarted according to its restart policy; other management of the container blocks until the hook completes"` + // PreStop is called immediately before a container is terminated. The reason for termination is + // passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. + PreStop *Handler `json:"preStop,omitempty" description:"called before a container is terminated; the container is terminated after the handler completes; other management of the container blocks until the hook completes"` +} + +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition; +// "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +type ContainerStateWaiting struct { + // Reason could be pulling image, + Reason string `json:"reason,omitempty" description:"(brief) reason the container is not yet running, such as pulling its image"` +} + +type ContainerStateRunning struct { + StartedAt util.Time `json:"startedAt,omitempty" description:"time at which the container was last (re-)started"` +} + +type ContainerStateTerminated struct { + ExitCode int `json:"exitCode" description:"exit status from the last termination of the container"` + Signal int `json:"signal,omitempty" description:"signal from the last termination of the container"` + Reason string `json:"reason,omitempty" description:"(brief) reason from the last termination of the container"` + Message string `json:"message,omitempty" description:"message regarding the last termination of the container"` + StartedAt util.Time `json:"startedAt,omitempty" description:"time at which previous execution of the container started"` + FinishedAt util.Time `json:"finishedAt,omitempty" description:"time at which the container last terminated"` + ContainerID string `json:"containerID,omitempty" description:"container's ID in the format 'docker://'"` +} + +// ContainerState holds a possible state of container. +// Only one of its members may be specified. +// If none of them is specified, the default one is ContainerStateWaiting. +type ContainerState struct { + Waiting *ContainerStateWaiting `json:"waiting,omitempty" description:"details about a waiting container"` + Running *ContainerStateRunning `json:"running,omitempty" description:"details about a running container"` + Termination *ContainerStateTerminated `json:"termination,omitempty" description:"details about a terminated container"` +} + +type ContainerStatus struct { + // Required: This must be a DNS_LABEL. Each container in a pod must have a unique name. + Name string `json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod; cannot be updated"` + // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states + // defined for container? + State ContainerState `json:"state,omitempty" description:"details about the container's current condition"` + LastTerminationState ContainerState `json:"lastState,omitempty" description:"details about the container's last termination condition"` + Ready bool `json:"ready" description:"specifies whether the container has passed its readiness probe"` + // Note that this is calculated from dead containers. But those containers are subject to + // garbage collection. This value will get capped at 5 by GC. + RestartCount int `json:"restartCount" description:"the number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed"` + // TODO(dchen1107): Which image the container is running with? + // The image the container is running + Image string `json:"image" description:"image of the container"` + ImageID string `json:"imageID" description:"ID of the container's image"` + ContainerID string `json:"containerID,omitempty" description:"container's ID in the format 'docker://'"` +} + +// PodPhase is a label for the condition of a pod at the current time. +type PodPhase string + +// These are the valid statuses of pods. +const ( + // PodPending means the pod has been accepted by the system, but one or more of the containers + // has not been started. This includes time before being bound to a node, as well as time spent + // pulling images onto the host. + PodPending PodPhase = "Pending" + // PodRunning means the pod has been bound to a node and all of the containers have been started. + // At least one container is still running or is in the process of being restarted. + PodRunning PodPhase = "Running" + // PodSucceeded means that all containers in the pod have voluntarily terminated + // with a container exit code of 0, and the system is not going to restart any of these containers. + PodSucceeded PodPhase = "Succeeded" + // PodFailed means that all containers in the pod have terminated, and at least one container has + // terminated in a failure (exited with a non-zero exit code or was stopped by the system). + PodFailed PodPhase = "Failed" + // PodUnknown means that for some reason the state of the pod could not be obtained, typically due + // to an error in communicating with the host of the pod. + PodUnknown PodPhase = "Unknown" +) + +// PodConditionType is a valid value for PodCondition.Type +type PodConditionType string + +// These are valid conditions of pod. +const ( + // PodReady means the pod is able to service requests and should be added to the + // load balancing pools of all matching services. + PodReady PodConditionType = "Ready" +) + +// TODO: add LastTransitionTime, Reason, Message to match NodeCondition api. +type PodCondition struct { + // Type is the type of the condition + Type PodConditionType `json:"type" description:"kind of the condition, currently only Ready"` + // Status is the status of the condition + Status ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` +} + +// RestartPolicy describes how the container should be restarted. +// Only one of the following restart policies may be specified. +// If none of the following policies is specified, the default one +// is RestartPolicyAlways. +type RestartPolicy string + +const ( + RestartPolicyAlways RestartPolicy = "Always" + RestartPolicyOnFailure RestartPolicy = "OnFailure" + RestartPolicyNever RestartPolicy = "Never" +) + +// DNSPolicy defines how a pod's DNS will be configured. +type DNSPolicy string + +const ( + // DNSClusterFirst indicates that the pod should use cluster DNS + // first, if it is available, then fall back on the default (as + // determined by kubelet) DNS settings. + DNSClusterFirst DNSPolicy = "ClusterFirst" + + // DNSDefault indicates that the pod should use the default (as + // determined by kubelet) DNS settings. + DNSDefault DNSPolicy = "Default" +) + +// PodSpec is a description of a pod +type PodSpec struct { + Volumes []Volume `json:"volumes" description:"list of volumes that can be mounted by containers belonging to the pod" patchStrategy:"merge" patchMergeKey:"name"` + // Required: there must be at least one container in a pod. + Containers []Container `json:"containers" description:"list of containers belonging to the pod; cannot be updated; containers cannot currently be added or removed; there must be at least one container in a Pod" patchStrategy:"merge" patchMergeKey:"name"` + RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" description:"restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever"` + // Optional: Set DNS policy. Defaults to "ClusterFirst" + DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty" description:"DNS policy for containers within the pod; one of 'ClusterFirst' or 'Default'"` + // NodeSelector is a selector which must be true for the pod to fit on a node + NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"` + + // Host is a request to schedule this pod onto a specific host. If it is non-empty, + // the the scheduler simply schedules this pod onto that host, assuming that it fits + // resource requirements. + Host string `json:"host,omitempty" description:"host requested for this pod"` + // Uses the host's network namespace. If this option is set, the ports that will be + // used must be specified. + // Optional: Default to false. + HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` +} + +// PodStatus represents information about the status of a pod. Status may trail the actual +// state of a system. +type PodStatus struct { + Phase PodPhase `json:"phase,omitempty" description:"current condition of the pod."` + Conditions []PodCondition `json:"Condition,omitempty" description:"current service state of pod" patchStrategy:"merge" patchMergeKey:"type"` + // A human readable message indicating details about why the pod is in this state. + Message string `json:"message,omitempty" description:"human readable message indicating details about why the pod is in this condition"` + + HostIP string `json:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` + PodIP string `json:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` + + // The list has one entry per container in the manifest. Each entry is currently the output + // of `docker inspect`. + ContainerStatuses []ContainerStatus `json:"containerStatuses,omitempty" description:"list of container statuses"` +} + +// PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded +type PodStatusResult struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + // Status represents the current information about a pod. This data may not be up + // to date. + Status PodStatus `json:"status,omitempty" description:"most recently observed status of the pod; populated by the system, read-only; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// Pod is a collection of containers that can run on a host. This resource is created +// by clients and scheduled onto hosts. +type Pod struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the behavior of a pod. + Spec PodSpec `json:"spec,omitempty" description:"specification of the desired behavior of the pod; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status represents the current information about a pod. This data may not be up + // to date. + Status PodStatus `json:"status,omitempty" description:"most recently observed status of the pod; populated by the system, read-only; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// PodList is a list of Pods. +type PodList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#types-kinds` + + Items []Pod `json:"items" description:"list of pods"` +} + +// PodTemplateSpec describes the data a pod should have when created from a template +type PodTemplateSpec struct { + // Metadata of the pods created from this template. + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the behavior of a pod. + Spec PodSpec `json:"spec,omitempty" description:"specification of the desired behavior of the pod; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// PodTemplate describes a template for creating copies of a predefined pod. +type PodTemplate struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Template defines the pods that will be created from this pod template + Template PodTemplateSpec `json:"template,omitempty" description:"the template of the desired behavior of the pod; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// PodTemplateList is a list of PodTemplates. +type PodTemplateList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []PodTemplate `json:"items" description:"list of pod templates"` +} + +// ReplicationControllerSpec is the specification of a replication controller. +type ReplicationControllerSpec struct { + // Replicas is the number of desired replicas. + Replicas int `json:"replicas" description:"number of replicas desired"` + + // Selector is a label query over pods that should match the Replicas count. + // If Selector is empty, it is defaulted to the labels present on the Pod template. + Selector map[string]string `json:"selector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template"` + + // TemplateRef is a reference to an object that describes the pod that will be created if + // insufficient replicas are detected. + TemplateRef *ObjectReference `json:"templateRef,omitempty" description:"reference to an object that describes the pod that will be created if insufficient replicas are detected"` + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. This takes precedence over a + // TemplateRef. + Template *PodTemplateSpec `json:"template,omitempty" description:"object that describes the pod that will be created if insufficient replicas are detected; takes precendence over templateRef"` +} + +// ReplicationControllerStatus represents the current status of a replication +// controller. +type ReplicationControllerStatus struct { + // Replicas is the number of actual replicas. + Replicas int `json:"replicas" description:"most recently oberved number of replicas"` +} + +// ReplicationController represents the configuration of a replication controller. +type ReplicationController struct { + TypeMeta `json:",inline"` + // If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the desired behavior of this replication controller. + Spec ReplicationControllerSpec `json:"spec,omitempty" description:"specification of the desired behavior of the replication controller; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status is the current status of this replication controller. This data may be + // out of date by some window of time. + Status ReplicationControllerStatus `json:"status,omitempty" description:"most recently observed status of the replication controller; populated by the system, read-only; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// ReplicationControllerList is a collection of replication controllers. +type ReplicationControllerList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []ReplicationController `json:"items" description:"list of replication controllers"` +} + +// Session Affinity Type string +type AffinityType string + +const ( + // AffinityTypeClientIP is the Client IP based. + AffinityTypeClientIP AffinityType = "ClientIP" + + // AffinityTypeNone - no session affinity. + AffinityTypeNone AffinityType = "None" +) + +// ServiceStatus represents the current status of a service +type ServiceStatus struct{} + +// ServiceSpec describes the attributes that a user creates on a service +type ServiceSpec struct { + // Required: The list of ports that are exposed by this service. + Ports []ServicePort `json:"ports" description:"ports exposed by the service"` + + // This service will route traffic to pods having labels matching this selector. If null, no endpoints will be automatically created. If empty, all pods will be selected. + Selector map[string]string `json:"selector" description:"label keys and values that must match in order to receive traffic for this service; if empty, all pods are selected, if not specified, endpoints must be manually specified"` + + // PortalIP is usually assigned by the master. If specified by the user + // we will try to respect it or else fail the request. This field can + // not be changed by updates. + // Valid values are None, empty string (""), or a valid IP address + // None can be specified for headless services when proxying is not required + PortalIP string `json:"portalIP,omitempty description: IP address of the service; usually assigned by the system; if specified, it will be allocated to the service if unused, and creation of the service will fail otherwise; cannot be updated; 'None' can be specified for a headless service when proxying is not required"` + + // CreateExternalLoadBalancer indicates whether a load balancer should be created for this service. + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" description:"set up a cloud-provider-specific load balancer on an external IP"` + + // PublicIPs are used by external load balancers, or can be set by + // users to handle external traffic that arrives at a node. + PublicIPs []string `json:"publicIPs,omitempty" description:"externally visible IPs (e.g. load balancers) that should be proxied to this service"` + + // Optional: Supports "ClientIP" and "None". Used to maintain session affinity. + SessionAffinity AffinityType `json:"sessionAffinity,omitempty" description:"enable client IP based session affinity; must be ClientIP or None; defaults to None"` +} + +type ServicePort struct { + // Optional if only one ServicePort is defined on this service: The + // name of this port within the service. This must be a DNS_LABEL. + // All ports within a ServiceSpec must have unique names. This maps to + // the 'Name' field in EndpointPort objects. + Name string `json:"name" description:"the name of this port; optional if only one port is defined"` + + // Optional: The IP protocol for this port. Supports "TCP" and "UDP", + // default is TCP. + Protocol Protocol `json:"protocol" description:"the protocol used by this port; must be UDP or TCP; TCP if unspecified"` + + // Required: The port that will be exposed by this service. + Port int `json:"port" description:"the port number that is exposed"` + + // Optional: The target port on pods selected by this service. + // If this is a string, it will be looked up as a named port in the + // target Pod's container ports. If this is not specified, the value + // of Port is used (an identity map). + TargetPort util.IntOrString `json:"targetPort" description:"the port to access on the pods targeted by the service; defaults to the service port"` +} + +// Service is a named abstraction of software service (for example, mysql) consisting of local port +// (for example 3306) that the proxy listens on, and the selector that determines which pods +// will answer requests sent through the proxy. +type Service struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the behavior of a service. + Spec ServiceSpec `json:"spec,omitempty" description:"specification of the desired behavior of the service; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status represents the current status of a service. + Status ServiceStatus `json:"status,omitempty" description:"most recently observed status of the service; populated by the system, read-only; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +const ( + // PortalIPNone - do not assign a portal IP + // no proxying required and no environment variables should be created for pods + PortalIPNone = "None" +) + +// ServiceList holds a list of services. +type ServiceList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []Service `json:"items" description:"list of services"` +} + +// Endpoints is a collection of endpoints that implement the actual service. Example: +// Name: "mysvc", +// Subsets: [ +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// }, +// { +// Addresses: [{"ip": "10.10.3.3"}], +// Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}] +// }, +// ] +type Endpoints struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // The set of all endpoints is the union of all subsets. + Subsets []EndpointSubset `json:"subsets" description:"sets of addresses and ports that comprise a service"` +} + +// EndpointSubset is a group of addresses with a common set of ports. The +// expanded set of endpoints is the Cartesian product of Addresses x Ports. +// For example, given: +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// } +// The resulting set of endpoints can be viewed as: +// a: [ 10.10.1.1:8675, 10.10.2.2:8675 ], +// b: [ 10.10.1.1:309, 10.10.2.2:309 ] +type EndpointSubset struct { + Addresses []EndpointAddress `json:"addresses,omitempty" description:"IP addresses which offer the related ports"` + Ports []EndpointPort `json:"ports,omitempty" description:"port numbers available on the related IP addresses"` +} + +// EndpointAddress is a tuple that describes single IP address. +type EndpointAddress struct { + // The IP of this endpoint. + // TODO: This should allow hostname or IP, see #4447. + IP string `json:"IP" description:"IP address of the endpoint"` + + // Optional: The kubernetes object related to the entry point. + TargetRef *ObjectReference `json:"targetRef,omitempty" description:"reference to object providing the endpoint"` +} + +// EndpointPort is a tuple that describes a single port. +type EndpointPort struct { + // The name of this port (corresponds to ServicePort.Name). Optional + // if only one port is defined. Must be a DNS_LABEL. + Name string `json:"name,omitempty" description:"name of this port"` + + // The port number. + Port int `json:"port" description:"port number of the endpoint"` + + // The IP protocol for this port. + Protocol Protocol `json:"protocol,omitempty" description:"protocol for this port; must be UDP or TCP; TCP if unspecified"` +} + +// EndpointsList is a list of endpoints. +type EndpointsList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []Endpoints `json:"items" description:"list of endpoints"` +} + +// NodeSpec describes the attributes that a node is created with. +type NodeSpec struct { + // PodCIDR represents the pod IP range assigned to the node + PodCIDR string `json:"podCIDR,omitempty" description:"pod IP range assigned to the node"` + // External ID of the node assigned by some machine database (e.g. a cloud provider) + ExternalID string `json:"externalID,omitempty" description:"external ID assigned to the node by some machine database (e.g. a cloud provider). Defaults to node name when empty."` + // Unschedulable controls node schedulability of new pods. By default node is schedulable. + Unschedulable bool `json:"unschedulable,omitempty" description:"disable pod scheduling on the node"` +} + +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID is the machine-id reported by the node + MachineID string `json:"machineID"` + // SystemUUID is the system-uuid reported by the node + SystemUUID string `json:"systemUUID"` + // BootID is the boot-id reported by the node + BootID string `json:"bootID" description:"boot id is the boot-id reported by the node"` + // Kernel version reported by the node + KernelVersion string `json:"kernelVersion" description:"Kernel version reported by the node from 'uname -r' (e.g. 3.16.0-0.bpo.4-amd64)"` + // OS image used reported by the node + OsImage string `json:"osImage" description:"OS image used reported by the node from /etc/os-release (e.g. Debian GNU/Linux 7 (wheezy))"` + // Container runtime version reported by the node + ContainerRuntimeVersion string `json:"containerRuntimeVersion" description:"Container runtime version reported by the node through runtime remote API (e.g. docker://1.5.0)"` + // Kubelet version reported by the node + KubeletVersion string `json:"kubeletVersion" description:"Kubelet version reported by the node"` + // Kube-proxy version reported by the node + KubeProxyVersion string `json:"KubeProxyVersion" description:"Kube-proxy version reported by the node"` +} + +// NodeStatus is information about the current status of a node. +type NodeStatus struct { + // Capacity represents the available resources of a node. + // see http://docs.k8s.io/resources.md for more details. + Capacity ResourceList `json:"capacity,omitempty" description:"compute resource capacity of the node; http://docs.k8s.io/resources.md"` + // NodePhase is the current lifecycle phase of the node. + Phase NodePhase `json:"phase,omitempty" description:"most recently observed lifecycle phase of the node"` + // Conditions is an array of current node conditions. + Conditions []NodeCondition `json:"conditions,omitempty" description:"list of node conditions observed" patchStrategy:"merge" patchMergeKey:"type"` + // Queried from cloud provider, if available. + Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node" patchStrategy:"merge" patchMergeKey:"type"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty"` +} + +type NodePhase string + +// These are the valid phases of node. +const ( + // NodePending means the node has been created/added by the system, but not configured. + NodePending NodePhase = "Pending" + // NodeRunning means the node has been configured and has Kubernetes components running. + NodeRunning NodePhase = "Running" + // NodeTerminated means the node has been removed from the cluster. + NodeTerminated NodePhase = "Terminated" +) + +type NodeConditionType string + +// These are valid conditions of node. Currently, we don't have enough information to decide +// node condition. In the future, we will add more. The proposed set of conditions are: +// NodeReachable, NodeLive, NodeReady, NodeSchedulable, NodeRunnable. +const ( + // NodeReady means kubelet is healthy and ready to accept pods. + NodeReady NodeConditionType = "Ready" +) + +type NodeCondition struct { + Type NodeConditionType `json:"type" description:"type of node condition, currently only Ready"` + Status ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` + LastHeartbeatTime util.Time `json:"lastHeartbeatTime,omitempty" description:"last time we got an update on a given condition"` + LastTransitionTime util.Time `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"` + Reason string `json:"reason,omitempty" description:"(brief) reason for the condition's last transition"` + Message string `json:"message,omitempty" description:"human readable message indicating details about last transition"` +} + +type NodeAddressType string + +// These are valid address type of node. +const ( + NodeHostName NodeAddressType = "Hostname" + NodeExternalIP NodeAddressType = "ExternalIP" + NodeInternalIP NodeAddressType = "InternalIP" +) + +type NodeAddress struct { + Type NodeAddressType `json:"type"` + Address string `json:"address"` +} + +// ResourceName is the name identifying various resources in a ResourceList. +type ResourceName string + +const ( + // CPU, in cores. (500m = .5 cores) + ResourceCPU ResourceName = "cpu" + // Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceMemory ResourceName = "memory" + // Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024) + ResourceStorage ResourceName = "storage" +) + +// ResourceList is a set of (resource name, quantity) pairs. +type ResourceList map[ResourceName]resource.Quantity + +// Node is a worker node in Kubernetes. +// The name of the node according to etcd is in ID. +type Node struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the behavior of a node. + Spec NodeSpec `json:"spec,omitempty" description:"specification of a node; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status describes the current status of a Node + Status NodeStatus `json:"status,omitempty" description:"most recently observed status of the node; populated by the system, read-only; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// NodeList is a list of minions. +type NodeList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []Node `json:"items" description:"list of nodes"` +} + +type FinalizerName string + +// These are internal finalizer values to Kubernetes, must be qualified name unless defined here +const ( + FinalizerKubernetes FinalizerName = "kubernetes" +) + +// NamespaceSpec describes the attributes on a Namespace +type NamespaceSpec struct { + // Finalizers is an opaque list of values that must be empty to permanently remove object from storage + Finalizers []FinalizerName `json:"finalizers,omitempty" description:"an opaque list of values that must be empty to permanently remove object from storage"` +} + +// NamespaceStatus is information about the current status of a Namespace. +type NamespaceStatus struct { + // Phase is the current lifecycle phase of the namespace. + Phase NamespacePhase `json:"phase,omitempty" description:"phase is the current lifecycle phase of the namespace"` +} + +type NamespacePhase string + +// These are the valid phases of a namespace. +const ( + // NamespaceActive means the namespace is available for use in the system + NamespaceActive NamespacePhase = "Active" + // NamespaceTerminating means the namespace is undergoing graceful termination + NamespaceTerminating NamespacePhase = "Terminating" +) + +// A namespace provides a scope for Names. +// Use of multiple namespaces is optional +type Namespace struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the behavior of the Namespace. + Spec NamespaceSpec `json:"spec,omitempty" description:"spec defines the behavior of the Namespace; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status describes the current status of a Namespace + Status NamespaceStatus `json:"status,omitempty" description:"status describes the current status of a Namespace; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// NamespaceList is a list of Namespaces. +type NamespaceList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Items is the list of Namespace objects in the list + Items []Namespace `json:"items" description:"items is the list of Namespace objects in the list"` +} + +// Binding ties one object to another - for example, a pod is bound to a node by a scheduler. +type Binding struct { + TypeMeta `json:",inline"` + // ObjectMeta describes the object that is being bound. + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Target is the object to bind to. + Target ObjectReference `json:"target" description:"an object to bind to"` +} + +// DeleteOptions may be provided when deleting an API object +type DeleteOptions struct { + TypeMeta `json:",inline"` + + // Optional duration in seconds before the object should be deleted. Value must be non-negative integer. + // The value zero indicates delete immediately. If this value is nil, the default grace period for the + // specified type will be used. + GracePeriodSeconds *int64 `json:"gracePeriodSeconds" description:"the duration in seconds to wait before deleting this object; defaults to a per object value if not specified; zero means delete immediately"` +} + +// ListOptions is the query options to a standard REST list call +type ListOptions struct { + TypeMeta `json:",inline"` + + // A selector based on labels + LabelSelector string `json:"labelSelector" description:"a selector to restrict the list of returned objects by their labels; defaults to everything"` + // A selector based on fields + FieldSelector string `json:"fieldSelector" description:"a selector to restrict the list of returned objects by their fields; defaults to everything"` + // If true, watch for changes to the selected resources + Watch bool `json:"watch" description:"watch for changes to the described resources and return them as a stream of add, update, and remove notifications; specify resourceVersion"` + // The desired resource version to watch + ResourceVersion string `json:"resourceVersion" description:"when specified with a watch call, shows changes that occur after that particular version of a resource; defaults to changes from the beginning of history"` +} + +// PodLogOptions is the query options for a Pod's logs REST call +type PodLogOptions struct { + TypeMeta `json:",inline"` + + // Container for which to return logs + Container string `json:"container,omitempty" description:"the container for which to stream logs; defaults to only container if there is one container in the pod"` + + // If true, follow the logs for the pod + Follow bool `json:"follow,omitempty" description:"follow the log stream of the pod; defaults to false"` +} + +// PodExecOptions is the query options to a Pod's remote exec call +type PodExecOptions struct { + TypeMeta `json:",inline"` + + // Stdin if true indicates that stdin is to be redirected for the exec call + Stdin bool `json:"stdin,omitempty" description:"redirect the standard input stream of the pod for this call; defaults to false"` + + // Stdout if true indicates that stdout is to be redirected for the exec call + Stdout bool `json:"stdout,omitempty" description:"redirect the standard output stream of the pod for this call; defaults to true"` + + // Stderr if true indicates that stderr is to be redirected for the exec call + Stderr bool `json:"stderr,omitempty" description:"redirect the standard error stream of the pod for this call; defaults to true"` + + // TTY if true indicates that a tty will be allocated for the exec call + TTY bool `json:"tty,omitempty" description:"allocate a terminal for this exec call; defaults to false"` + + // Container in which to execute the command. + Container string `json:"container,omitempty" description:"the container in which to execute the command. Defaults to only container if there is only one container in the pod."` + + // Command is the remote command to execute + Command string `json:"command" description:"the command to execute"` +} + +// PodProxyOptions is the query options to a Pod's proxy call +type PodProxyOptions struct { + TypeMeta `json:",inline"` + + // Path is the URL path to use for the current proxy request + Path string `json:"path,omitempty" description:"URL path to use in proxy request to pod"` +} + +// Status is a return value for calls that don't return other objects. +type Status struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // One of: "Success" or "Failure" + Status string `json:"status,omitempty" description:"status of the operation; either Success, or Failure"` + // A human-readable description of the status of this operation. + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` + // A machine-readable description of why this operation is in the + // "Failure" status. If this value is empty there + // is no information available. A Reason clarifies an HTTP status + // code but does not override it. + Reason StatusReason `json:"reason,omitempty" description:"machine-readable description of why this operation is in the 'Failure' status; if this value is empty there is no information available; a reason clarifies an HTTP status code but does not override it"` + // Extended data associated with the reason. Each reason may define its + // own extended details. This field is optional and the data returned + // is not guaranteed to conform to any schema except that defined by + // the reason type. + Details *StatusDetails `json:"details,omitempty" description:"extended data associated with the reason; each reason may define its own extended details; this field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type"` + // Suggested HTTP return code for this status, 0 if not set. + Code int `json:"code,omitempty" description:"suggested HTTP return code for this status; 0 if not set"` +} + +// StatusDetails is a set of additional properties that MAY be set by the +// server to provide additional information about a response. The Reason +// field of a Status object defines what attributes will be set. Clients +// must ignore fields that do not match the defined type of each attribute, +// and should assume that any attribute may be empty, invalid, or under +// defined. +type StatusDetails struct { + // The ID attribute of the resource associated with the status StatusReason + // (when there is a single ID which can be described). + ID string `json:"id,omitempty" description:"the ID attribute of the resource associated with the status StatusReason (when there is a single ID which can be described)"` + // The kind attribute of the resource associated with the status StatusReason. + // On some operations may differ from the requested resource Kind. + Kind string `json:"kind,omitempty" description:"the kind attribute of the resource associated with the status StatusReason; on some operations may differ from the requested resource Kind"` + // The Causes array includes more details associated with the StatusReason + // failure. Not all StatusReasons may provide detailed causes. + Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"` + // If specified, the time in seconds before the operation should be retried. + RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"` +} + +// Values of Status.Status +const ( + StatusSuccess = "Success" + StatusFailure = "Failure" +) + +// StatusReason is an enumeration of possible failure causes. Each StatusReason +// must map to a single HTTP status code, but multiple reasons may map +// to the same HTTP status code. +// TODO: move to apiserver +type StatusReason string + +const ( + // StatusReasonUnknown means the server has declined to indicate a specific reason. + // The details field may contain other information about this error. + // Status code 500. + StatusReasonUnknown StatusReason = "" + + // StatusReasonNotFound means one or more resources required for this operation + // could not be found. + // Details (optional): + // "kind" string - the kind attribute of the missing resource + // on some operations may differ from the requested + // resource. + // "id" string - the identifier of the missing resource + // Status code 404 + StatusReasonNotFound StatusReason = "NotFound" + + // StatusReasonAlreadyExists means the resource you are creating already exists. + // Details (optional): + // "kind" string - the kind attribute of the conflicting resource + // "id" string - the identifier of the conflicting resource + // Status code 409 + StatusReasonAlreadyExists StatusReason = "AlreadyExists" + + // StatusReasonConflict means the requested update operation cannot be completed + // due to a conflict in the operation. The client may need to alter the request. + // Each resource may define custom details that indicate the nature of the + // conflict. + // Status code 409 + StatusReasonConflict StatusReason = "Conflict" + + // StatusReasonInvalid means the requested create or update operation cannot be + // completed due to invalid data provided as part of the request. The client may + // need to alter the request. When set, the client may use the StatusDetails + // message field as a summary of the issues encountered. + // Details (optional): + // "kind" string - the kind attribute of the invalid resource + // "id" string - the identifier of the invalid resource + // "causes" - one or more StatusCause entries indicating the data in the + // provided resource that was invalid. The code, message, and + // field attributes will be set. + // Status code 422 + StatusReasonInvalid StatusReason = "Invalid" + + // StatusReasonServerTimeout means the server can be reached and understood the request, + // but cannot complete the action in a reasonable time. The client should retry the request. + // This is may be due to temporary server load or a transient communication issue with + // another server. Status code 500 is used because the HTTP spec provides no suitable + // server-requested client retry and the 5xx class represents actionable errors. + // Details (optional): + // "kind" string - the kind attribute of the resource being acted on. + // "id" string - the operation that is being attempted. + // Status code 500 + StatusReasonServerTimeout StatusReason = "ServerTimeout" +) + +// StatusCause provides more information about an api.Status failure, including +// cases when multiple errors are encountered. +type StatusCause struct { + // A machine-readable description of the cause of the error. If this value is + // empty there is no information available. + Type CauseType `json:"reason,omitempty" description:"machine-readable description of the cause of the error; if this value is empty there is no information available"` + // A human-readable description of the cause of the error. This field may be + // presented as-is to a reader. + Message string `json:"message,omitempty" description:"human-readable description of the cause of the error; this field may be presented as-is to a reader"` + // The field of the resource that has caused this error, as named by its JSON + // serialization. May include dot and postfix notation for nested attributes. + // Arrays are zero-indexed. Fields may appear more than once in an array of + // causes due to fields having multiple errors. + // Optional. + // + // Examples: + // "name" - the field "name" on the current resource + // "items[0].name" - the field "name" on the first array entry in "items" + Field string `json:"field,omitempty" description:"field of the resource that has caused this error, as named by its JSON serialization; may include dot and postfix notation for nested attributes; arrays are zero-indexed; fields may appear more than once in an array of causes due to fields having multiple errors"` +} + +// CauseType is a machine readable value providing more detail about what +// occured in a status response. An operation may have multiple causes for a +// status (whether Failure or Success). +type CauseType string + +const ( + // CauseTypeFieldValueNotFound is used to report failure to find a requested value + // (e.g. looking up an ID). + CauseTypeFieldValueNotFound CauseType = "FieldValueNotFound" + // CauseTypeFieldValueRequired is used to report required values that are not + // provided (e.g. empty strings, null values, or empty arrays). + CauseTypeFieldValueRequired CauseType = "FieldValueRequired" + // CauseTypeFieldValueDuplicate is used to report collisions of values that must be + // unique (e.g. unique IDs). + CauseTypeFieldValueDuplicate CauseType = "FieldValueDuplicate" + // CauseTypeFieldValueInvalid is used to report malformed values (e.g. failed regex + // match). + CauseTypeFieldValueInvalid CauseType = "FieldValueInvalid" + // CauseTypeFieldValueNotSupported is used to report valid (as per formatting rules) + // values that can not be handled (e.g. an enumerated string). + CauseTypeFieldValueNotSupported CauseType = "FieldValueNotSupported" +) + +// ObjectReference contains enough information to let you inspect or modify the referred object. +type ObjectReference struct { + Kind string `json:"kind,omitempty" description:"kind of the referent"` + Namespace string `json:"namespace,omitempty" description:"namespace of the referent"` + Name string `json:"name,omitempty" description:"name of the referent"` + UID types.UID `json:"uid,omitempty" description:"uid of the referent"` + APIVersion string `json:"apiVersion,omitempty" description:"API version of the referent"` + ResourceVersion string `json:"resourceVersion,omitempty" description:"specific resourceVersion to which this reference is made, if any: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"` + + // Optional. If referring to a piece of an object instead of an entire object, this string + // should contain information to identify the sub-object. For example, if the object + // reference is to a container within a pod, this would take on a value like: + // "spec.containers{name}" (where "name" refers to the name of the container that triggered + // the event) or if no container name is specified "spec.containers[2]" (container with + // index 2 in this pod). This syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` +} + +type EventSource struct { + // Component from which the event is generated. + Component string `json:"component,omitempty" description:"component that generated the event"` + // Host name on which the event is generated. + Host string `json:"host,omitempty" description:"name of the host where the event is generated"` +} + +// Event is a report of an event somewhere in the cluster. +// TODO: Decide whether to store these separately or with the object they apply to. +type Event struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Required. The object that this event is about. + InvolvedObject ObjectReference `json:"involvedObject,omitempty" description:"object this event is about"` + + // Optional; this should be a short, machine understandable string that gives the reason + // for this event being generated. + // TODO: provide exact specification for format. + Reason string `json:"reason,omitempty" description:"short, machine understandable string that gives the reason for the transition into the object's current status"` + + // Optional. A human-readable description of the status of this operation. + // TODO: decide on maximum length. + Message string `json:"message,omitempty" description:"human-readable description of the status of this operation"` + + // Optional. The component reporting this event. Should be a short machine understandable string. + Source EventSource `json:"source,omitempty" description:"component reporting this event"` + + // The time at which the event was first recorded. (Time of server receipt is in TypeMeta.) + FirstTimestamp util.Time `json:"firstTimestamp,omitempty" description:"the time at which the event was first recorded"` + + // The time at which the most recent occurance of this event was recorded. + LastTimestamp util.Time `json:"lastTimestamp,omitempty" description:"the time at which the most recent occurance of this event was recorded"` + + // The number of times this event has occurred. + Count int `json:"count,omitempty" description:"the number of times this event has occurred"` +} + +// EventList is a list of events. +type EventList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []Event `json:"items" description:"list of events"` +} + +// List holds a list of objects, which may not be known by the server. +type List struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []runtime.RawExtension `json:"items" description:"list of objects"` +} + +// A type of object that is limited +type LimitType string + +const ( + // Limit that applies to all pods in a namespace + LimitTypePod LimitType = "Pod" + // Limit that applies to all containers in a namespace + LimitTypeContainer LimitType = "Container" +) + +// LimitRangeItem defines a min/max usage limit for any resource that matches on kind +type LimitRangeItem struct { + // Type of resource that this limit applies to + Type LimitType `json:"type,omitempty" description:"type of resource that this limit applies to"` + // Max usage constraints on this kind by resource name + Max ResourceList `json:"max,omitempty" description:"max usage constraints on this kind by resource name"` + // Min usage constraints on this kind by resource name + Min ResourceList `json:"min,omitempty" description:"min usage constraints on this kind by resource name"` + // Default usage constraints on this kind by resource name + Default ResourceList `json:"default,omitempty" description:"default values on this kind by resource name if omitted"` +} + +// LimitRangeSpec defines a min/max usage limit for resources that match on kind +type LimitRangeSpec struct { + // Limits is the list of LimitRangeItem objects that are enforced + Limits []LimitRangeItem `json:"limits" description:"limits is the list of LimitRangeItem objects that are enforced"` +} + +// LimitRange sets resource usage limits for each kind of resource in a Namespace +type LimitRange struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the limits enforced + Spec LimitRangeSpec `json:"spec,omitempty" description:"spec defines the limits enforced; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// LimitRangeList is a list of LimitRange items. +type LimitRangeList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Items is a list of LimitRange objects + Items []LimitRange `json:"items" description:"items is a list of LimitRange objects"` +} + +// The following identify resource constants for Kubernetes object types +const ( + // Pods, number + ResourcePods ResourceName = "pods" + // Services, number + ResourceServices ResourceName = "services" + // ReplicationControllers, number + ResourceReplicationControllers ResourceName = "replicationcontrollers" + // ResourceQuotas, number + ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" +) + +// ResourceQuotaSpec defines the desired hard limits to enforce for Quota +type ResourceQuotaSpec struct { + // Hard is the set of desired hard limits for each named resource + Hard ResourceList `json:"hard,omitempty" description:"hard is the set of desired hard limits for each named resource"` +} + +// ResourceQuotaStatus defines the enforced hard limits and observed use +type ResourceQuotaStatus struct { + // Hard is the set of enforced hard limits for each named resource + Hard ResourceList `json:"hard,omitempty" description:"hard is the set of enforced hard limits for each named resource"` + // Used is the current observed total usage of the resource in the namespace + Used ResourceList `json:"used,omitempty" description:"used is the current observed total usage of the resource in the namespace"` +} + +// ResourceQuota sets aggregate quota restrictions enforced per namespace +type ResourceQuota struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Spec defines the desired quota + Spec ResourceQuotaSpec `json:"spec,omitempty" description:"spec defines the desired quota; http://docs.k8s.io/api-conventions.md#spec-and-status"` + + // Status defines the actual enforced quota and its current usage + Status ResourceQuotaStatus `json:"status,omitempty" description:"status defines the actual enforced quota and current usage; http://docs.k8s.io/api-conventions.md#spec-and-status"` +} + +// ResourceQuotaList is a list of ResourceQuota items +type ResourceQuotaList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Items is a list of ResourceQuota objects + Items []ResourceQuota `json:"items" description:"items is a list of ResourceQuota objects"` +} + +// Secret holds secret data of a certain type. The total bytes of the values in +// the Data field must be less than MaxSecretSize bytes. +type Secret struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + // Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. + // The serialized form of the secret data is a base64 encoded string, + // representing the arbitrary (possibly non-string) data value here. + Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. Each value must be a base64 encoded string"` + + // Used to facilitate programmatic handling of secret data. + Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"` +} + +const MaxSecretSize = 1 * 1024 * 1024 + +type SecretType string + +const ( + SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data +) + +type SecretList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []Secret `json:"items" description:"items is a list of secret objects"` +} + +// Type and constants for component health validation. +type ComponentConditionType string + +// These are the valid conditions for the component. +const ( + ComponentHealthy ComponentConditionType = "Healthy" +) + +type ComponentCondition struct { + Type ComponentConditionType `json:"type" description:"type of component condition, currently only Healthy"` + Status ConditionStatus `json:"status" description:"current status of this component condition, one of True, False, Unknown"` + Message string `json:"message,omitempty" description:"health check message received from the component"` + Error string `json:"error,omitempty" description:"error code from health check attempt (if any)"` +} + +// ComponentStatus (and ComponentStatusList) holds the cluster validation info. +type ComponentStatus struct { + TypeMeta `json:",inline"` + ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Conditions []ComponentCondition `json:"conditions,omitempty" description:"list of component conditions observed" patchStrategy:"merge" patchMergeKey:"type"` +} + +type ComponentStatusList struct { + TypeMeta `json:",inline"` + ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"` + + Items []ComponentStatus `json:"items" description:"list of component status objects"` +} diff --git a/pkg/master/master.go b/pkg/master/master.go index 106eda491a0..a40b9a0f49e 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -32,6 +32,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" @@ -88,6 +89,8 @@ type Config struct { EnableSwaggerSupport bool // allow v1beta3 to be conditionally disabled DisableV1Beta3 bool + // allow v1 to be conditionally enabled + EnableV1 bool // allow downstream consumers to disable the index route EnableIndex bool EnableProfiling bool @@ -150,6 +153,7 @@ type Master struct { admissionControl admission.Interface masterCount int v1beta3 bool + v1 bool requestContextMapper api.RequestContextMapper // External host is the name that should be used in external (public internet) URLs for this master @@ -288,6 +292,7 @@ func New(c *Config) *Master { authorizer: c.Authorizer, admissionControl: c.AdmissionControl, v1beta3: !c.DisableV1Beta3, + v1: c.EnableV1, requestContextMapper: c.RequestContextMapper, cacheTimeout: c.CacheTimeout, @@ -448,7 +453,13 @@ func (m *Master) init(c *Config) { if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1beta3: %v", err) } - apiVersions = []string{"v1beta1", "v1beta2", "v1beta3"} + apiVersions = append(apiVersions, "v1beta3") + } + if m.v1 { + if err := m.api_v1().InstallREST(m.handlerContainer); err != nil { + glog.Fatalf("Unable to setup API v1: %v", err) + } + apiVersions = append(apiVersions, "v1") } apiserver.InstallSupport(m.muxHelper, m.rootWebService) @@ -667,3 +678,19 @@ func (m *Master) api_v1beta3() *apiserver.APIGroupVersion { version.Codec = v1beta3.Codec return version } + +// api_v1 returns the resources and codec for API version v1. +func (m *Master) api_v1() *apiserver.APIGroupVersion { + storage := make(map[string]rest.Storage) + for k, v := range m.storage { + if k == "minions" { + continue + } + storage[strings.ToLower(k)] = v + } + version := m.defaultAPIGroupVersion() + version.Storage = storage + version.Version = "v1" + version.Codec = v1.Codec + return version +}