Merge pull request #2097 from markturansky/v1beta3_podrefactor

Refactor internal API for Pods to match v1beta3
This commit is contained in:
Clayton Coleman
2014-11-18 15:28:58 -05:00
36 changed files with 569 additions and 573 deletions

View File

@@ -81,7 +81,7 @@ func init() {
// Convert Pod to BoundPod
func(in *Pod, out *BoundPod, s conversion.Scope) error {
if err := s.Convert(&in.DesiredState.Manifest, out, 0); err != nil {
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
// Only copy a subset of fields, and override manifest attributes with the pod

View File

@@ -45,6 +45,16 @@ func Codec() runtime.Codec {
return interfaces.Codec
}
// Converter returns the api.Scheme for the API version to test against, as set by the
// KUBE_API_VERSION env var.
func Converter() runtime.ObjectConvertor {
interfaces, err := latest.InterfacesFor(Version())
if err != nil {
panic(err)
}
return interfaces.ObjectConvertor
}
// MetadataAccessor returns the MetadataAccessor for the API version to test against,
// as set by the KUBE_API_VERSION env var.
func MetadataAccessor() meta.MetadataAccessor {

View File

@@ -455,15 +455,37 @@ type PodSpec struct {
NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"`
}
// PodStatus represents information about the status of a pod. Status may trail the actual
// state of a system.
type PodStatus struct {
Condition PodCondition `json:"condition,omitempty" yaml:"condition,omitempty"`
// Host is the name of the node that this Pod is currently bound to, or empty if no
// assignment has been done.
Host string `json:"host,omitempty" yaml:"host,omitempty"`
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
// The key of this map is the *name* of the container within the manifest; it has one
// entry per container in the manifest. The value of this map is currently the output
// of `docker inspect`. This output format is *not* final and should not be relied
// upon.
// TODO: Make real decisions about what our info should look like. Re-enable fuzz test
// when we have done this.
Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
}
// Pod is a collection of containers, used as either input (create, update) or as output (list, get).
type Pod struct {
TypeMeta `json:",inline" yaml:",inline"`
ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
// NodeSelector is a selector which must be true for the pod to fit on a node
NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"`
// Spec defines the behavior of a pod.
Spec PodSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
// Status represents the current information about a pod. This data may not be up
// to date.
Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"`
}
// PodTemplateSpec describes the data a pod should have when created from a template

View File

@@ -160,6 +160,32 @@ func init() {
return nil
},
func(in *newer.PodStatus, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in.Condition, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.Info, 0); err != nil {
return err
}
out.Host = in.Host
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *PodState, out *newer.PodStatus, s conversion.Scope) error {
if err := s.Convert(&in.Status, &out.Condition, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.Info, 0); err != nil {
return err
}
out.Host = in.Host
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
// Convert all to the new PodCondition constants
func(in *newer.PodCondition, out *PodStatus, s conversion.Scope) error {
switch *in {
@@ -189,7 +215,7 @@ func init() {
case PodRunning:
*out = newer.PodRunning
case PodTerminated:
// Older API versions did not contain enough info to map to PodFailed
// Older API versions did not contain enough info to map to PodSucceeded
*out = newer.PodFailed
default:
return errors.New("The string provided is not a valid PodCondition constant value")
@@ -208,15 +234,13 @@ func init() {
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.DesiredState, 0); err != nil {
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
if err := s.Convert(&in.CurrentState, &out.CurrentState, 0); err != nil {
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.NodeSelector, 0); err != nil {
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
return nil
@@ -231,15 +255,13 @@ func init() {
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.DesiredState, 0); err != nil {
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.CurrentState, &out.CurrentState, 0); err != nil {
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.NodeSelector, 0); err != nil {
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
return nil
@@ -326,6 +348,19 @@ func init() {
return nil
},
func(in *newer.PodSpec, out *BoundPod, s conversion.Scope) error {
if err := s.Convert(&in, &out.Spec, 0); err != nil {
return err
}
return nil
},
func(in *BoundPod, out *newer.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Spec, &out, 0); err != nil {
return err
}
return nil
},
func(in *newer.PodSpec, out *ContainerManifest, s conversion.Scope) error {
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
return err

View File

@@ -119,7 +119,7 @@ func init() {
case PodRunning:
*out = newer.PodRunning
case PodTerminated:
// Older API versions did not contain enough info to map to PodFailed
// Older API versions did not contain enough info to map to PodSucceeded
*out = newer.PodFailed
default:
return errors.New("The string provided is not a valid PodCondition constant value")
@@ -138,15 +138,13 @@ func init() {
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.DesiredState, 0); err != nil {
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
if err := s.Convert(&in.CurrentState, &out.CurrentState, 0); err != nil {
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.NodeSelector, 0); err != nil {
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
return nil
@@ -161,15 +159,13 @@ func init() {
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.DesiredState, 0); err != nil {
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.CurrentState, &out.CurrentState, 0); err != nil {
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.NodeSelector, 0); err != nil {
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
return nil
@@ -282,6 +278,43 @@ func init() {
return nil
},
func(in *newer.PodStatus, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in.Condition, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.Info, 0); err != nil {
return err
}
out.Host = in.Host
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *PodState, out *newer.PodStatus, s conversion.Scope) error {
if err := s.Convert(&in.Status, &out.Condition, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.Info, 0); err != nil {
return err
}
out.Host = in.Host
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *newer.PodSpec, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in, &out.Manifest, 0); err != nil {
return err
}
return nil
},
func(in *PodState, out *newer.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Manifest, &out, 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

View File

@@ -345,7 +345,7 @@ func ValidatePod(pod *api.Pod) errs.ValidationErrorList {
if !util.IsDNSSubdomain(pod.Namespace) {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", pod.Namespace))
}
allErrs = append(allErrs, ValidatePodState(&pod.DesiredState).Prefix("desiredState")...)
allErrs = append(allErrs, ValidatePodSpec(&pod.Spec).Prefix("spec")...)
allErrs = append(allErrs, validateLabels(pod.Labels)...)
return allErrs
}
@@ -383,8 +383,8 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
allErrs = append(allErrs, errs.NewFieldInvalid("name", newPod.Name))
}
if len(newPod.DesiredState.Manifest.Containers) != len(oldPod.DesiredState.Manifest.Containers) {
allErrs = append(allErrs, errs.NewFieldInvalid("DesiredState.Manifest.Containers", newPod.DesiredState.Manifest.Containers))
if len(newPod.Spec.Containers) != len(oldPod.Spec.Containers) {
allErrs = append(allErrs, errs.NewFieldInvalid("spec.containers", newPod.Spec.Containers))
return allErrs
}
pod := *newPod
@@ -392,13 +392,13 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
pod.ResourceVersion = oldPod.ResourceVersion
// Tricky, we need to copy the container list so that we don't overwrite the update
var newContainers []api.Container
for ix, container := range pod.DesiredState.Manifest.Containers {
container.Image = oldPod.DesiredState.Manifest.Containers[ix].Image
for ix, container := range pod.Spec.Containers {
container.Image = oldPod.Spec.Containers[ix].Image
newContainers = append(newContainers, container)
}
pod.DesiredState.Manifest.Containers = newContainers
if !reflect.DeepEqual(pod.DesiredState.Manifest, oldPod.DesiredState.Manifest) {
allErrs = append(allErrs, errs.NewFieldInvalid("DesiredState.Manifest.Containers", newPod.DesiredState.Manifest.Containers))
pod.Spec.Containers = newContainers
if !reflect.DeepEqual(pod.Spec, oldPod.Spec) {
allErrs = append(allErrs, errs.NewFieldInvalid("spec.containers", newPod.Spec.Containers))
}
return allErrs
}

View File

@@ -374,13 +374,9 @@ func TestValidatePod(t *testing.T) {
"foo": "bar",
},
},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Version: "v1beta1",
ID: "abc",
RestartPolicy: api.RestartPolicy{
Always: &api.RestartPolicyAlways{},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicy{
Always: &api.RestartPolicyAlways{},
},
},
})
@@ -395,28 +391,16 @@ func TestValidatePod(t *testing.T) {
"foo": "bar",
},
},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{Version: "v1beta1", ID: "abc"},
},
Spec: api.PodSpec{},
})
if len(errs) != 0 {
t.Errorf("Unexpected non-zero error list: %#v", errs)
}
errs = ValidatePod(&api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo", Namespace: api.NamespaceDefault,
Labels: map[string]string{
"foo": "bar",
},
},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Version: "v1beta1",
ID: "abc",
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{},
Never: &api.RestartPolicyNever{}},
},
errs = ValidatePodSpec(&api.PodSpec{
RestartPolicy: api.RestartPolicy{
Always: &api.RestartPolicyAlways{},
Never: &api.RestartPolicyNever{},
},
})
if len(errs) != 1 {
@@ -436,9 +420,7 @@ func TestValidatePod(t *testing.T) {
"rfc952-24chars-orless": "bar", //good label
},
},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{Version: "v1beta1", ID: "abc"},
},
Spec: api.PodSpec{},
})
if len(errs) != 5 {
t.Errorf("Unexpected non-zero error list: %#v", errs)
@@ -488,27 +470,23 @@ func TestValidatePodUpdate(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V1",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V1",
},
},
},
},
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V2",
},
{
Image: "bar:V2",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V2",
},
{
Image: "bar:V2",
},
},
},
@@ -519,24 +497,20 @@ func TestValidatePodUpdate(t *testing.T) {
{
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V1",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V1",
},
},
},
},
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V2",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V2",
},
},
},
@@ -547,26 +521,22 @@ func TestValidatePodUpdate(t *testing.T) {
{
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V1",
CPU: 100,
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V1",
CPU: 100,
},
},
},
},
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V2",
CPU: 1000,
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V2",
CPU: 1000,
},
},
},
@@ -577,14 +547,12 @@ func TestValidatePodUpdate(t *testing.T) {
{
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V1",
Ports: []api.Port{
{HostPort: 8080, ContainerPort: 80},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V1",
Ports: []api.Port{
{HostPort: 8080, ContainerPort: 80},
},
},
},
@@ -592,14 +560,12 @@ func TestValidatePodUpdate(t *testing.T) {
},
api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{
Image: "foo:V2",
Ports: []api.Port{
{HostPort: 8000, ContainerPort: 80},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Image: "foo:V2",
Ports: []api.Port{
{HostPort: 8000, ContainerPort: 80},
},
},
},