Introducing ReplicaSet, a new incarnation of Replication Controller.

This commit adds the API types, conversion, validation and defaulting code.
This commit is contained in:
Madhusudan.C.S 2015-11-11 17:15:06 -08:00
parent 2374a3225a
commit 572abe1c50
15 changed files with 5859 additions and 1927 deletions

View File

@ -1558,6 +1558,69 @@ func deepCopy_extensions_NodeUtilization(in NodeUtilization, out *NodeUtilizatio
return nil
}
func deepCopy_extensions_ReplicaSet(in ReplicaSet, out *ReplicaSet, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := deepCopy_extensions_ReplicaSetSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := deepCopy_extensions_ReplicaSetStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func deepCopy_extensions_ReplicaSetList(in ReplicaSetList, out *ReplicaSetList, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]ReplicaSet, len(in.Items))
for i := range in.Items {
if err := deepCopy_extensions_ReplicaSet(in.Items[i], &out.Items[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func deepCopy_extensions_ReplicaSetSpec(in ReplicaSetSpec, out *ReplicaSetSpec, c *conversion.Cloner) error {
out.Replicas = in.Replicas
if in.Selector != nil {
out.Selector = new(LabelSelector)
if err := deepCopy_extensions_LabelSelector(*in.Selector, out.Selector, c); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.Template != nil {
out.Template = new(api.PodTemplateSpec)
if err := deepCopy_api_PodTemplateSpec(*in.Template, out.Template, c); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}
func deepCopy_extensions_ReplicaSetStatus(in ReplicaSetStatus, out *ReplicaSetStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func deepCopy_extensions_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
@ -1801,6 +1864,10 @@ func init() {
deepCopy_extensions_LabelSelector,
deepCopy_extensions_LabelSelectorRequirement,
deepCopy_extensions_NodeUtilization,
deepCopy_extensions_ReplicaSet,
deepCopy_extensions_ReplicaSetList,
deepCopy_extensions_ReplicaSetSpec,
deepCopy_extensions_ReplicaSetStatus,
deepCopy_extensions_ReplicationControllerDummy,
deepCopy_extensions_RollingUpdateDaemonSet,
deepCopy_extensions_RollingUpdateDeployment,

View File

@ -68,6 +68,8 @@ func addKnownTypes(scheme *runtime.Scheme) {
&api.ListOptions{},
&ConfigMap{},
&ConfigMapList{},
&ReplicaSet{},
&ReplicaSetList{},
&api.ExportOptions{},
)
}
@ -92,3 +94,5 @@ func (obj *Ingress) GetObjectKind() unversioned.ObjectKind {
func (obj *IngressList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ConfigMap) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ConfigMapList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ReplicaSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ReplicaSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

File diff suppressed because it is too large Load Diff

View File

@ -796,3 +796,51 @@ type ConfigMapList struct {
// Items is the list of ConfigMaps.
Items []ConfigMap `json:"items,omitempty"`
}
// ReplicaSet represents the configuration of a replica set.
type ReplicaSet struct {
unversioned.TypeMeta `json:",inline"`
api.ObjectMeta `json:"metadata,omitempty"`
// Spec defines the desired behavior of this ReplicaSet.
Spec ReplicaSetSpec `json:"spec,omitempty"`
// Status is the current status of this ReplicaSet. This data may be
// out of date by some window of time.
Status ReplicaSetStatus `json:"status,omitempty"`
}
// ReplicaSetList is a collection of ReplicaSets.
type ReplicaSetList struct {
unversioned.TypeMeta `json:",inline"`
unversioned.ListMeta `json:"metadata,omitempty"`
Items []ReplicaSet `json:"items"`
}
// ReplicaSetSpec is the specification of a ReplicaSet.
// As the internal representation of a ReplicaSet, it must have
// a Template set.
type ReplicaSetSpec struct {
// Replicas is the number of desired replicas.
Replicas int `json:"replicas"`
// Selector is a label query over pods that should match the replica count.
// Must match in order to be controlled.
// If empty, defaulted to labels on pod template.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
Selector *LabelSelector `json:"selector,omitempty"`
// Template is the object that describes the pod that will be created if
// insufficient replicas are detected.
Template *api.PodTemplateSpec `json:"template,omitempty"`
}
// ReplicaSetStatus represents the current status of a ReplicaSet.
type ReplicaSetStatus struct {
// Replicas is the number of actual replicas.
Replicas int `json:"replicas"`
// ObservedGeneration is the most recent generation observed by the controller.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

View File

@ -44,6 +44,8 @@ func addConversionFuncs(scheme *runtime.Scheme) {
Convert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy,
Convert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet,
Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet,
Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec,
Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec,
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
@ -511,3 +513,54 @@ func Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet
out.MinReadySeconds = int(in.MinReadySeconds)
return nil
}
func Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec(in *extensions.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetSpec))(in)
}
out.Replicas = new(int32)
*out.Replicas = int32(in.Replicas)
if in.Selector != nil {
out.Selector = new(LabelSelector)
if err := Convert_extensions_LabelSelector_To_v1beta1_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.Template != nil {
out.Template = new(v1.PodTemplateSpec)
if err := Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}
func Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec(in *ReplicaSetSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicaSetSpec))(in)
}
if in.Replicas != nil {
out.Replicas = int(*in.Replicas)
}
if in.Selector != nil {
out.Selector = new(extensions.LabelSelector)
if err := Convert_v1beta1_LabelSelector_To_extensions_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.Template != nil {
out.Template = new(api.PodTemplateSpec)
if err := Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in.Template, out.Template, s); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}

View File

@ -3304,6 +3304,97 @@ func Convert_extensions_NodeUtilization_To_v1beta1_NodeUtilization(in *extension
return autoConvert_extensions_NodeUtilization_To_v1beta1_NodeUtilization(in, out, s)
}
func autoConvert_extensions_ReplicaSet_To_v1beta1_ReplicaSet(in *extensions.ReplicaSet, out *ReplicaSet, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSet))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_extensions_ReplicaSetStatus_To_v1beta1_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_extensions_ReplicaSet_To_v1beta1_ReplicaSet(in *extensions.ReplicaSet, out *ReplicaSet, s conversion.Scope) error {
return autoConvert_extensions_ReplicaSet_To_v1beta1_ReplicaSet(in, out, s)
}
func autoConvert_extensions_ReplicaSetList_To_v1beta1_ReplicaSetList(in *extensions.ReplicaSetList, out *ReplicaSetList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetList))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]ReplicaSet, len(in.Items))
for i := range in.Items {
if err := Convert_extensions_ReplicaSet_To_v1beta1_ReplicaSet(&in.Items[i], &out.Items[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_extensions_ReplicaSetList_To_v1beta1_ReplicaSetList(in *extensions.ReplicaSetList, out *ReplicaSetList, s conversion.Scope) error {
return autoConvert_extensions_ReplicaSetList_To_v1beta1_ReplicaSetList(in, out, s)
}
func autoConvert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec(in *extensions.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetSpec))(in)
}
if err := s.Convert(&in.Replicas, &out.Replicas, 0); err != nil {
return err
}
// unable to generate simple pointer conversion for extensions.LabelSelector -> v1beta1.LabelSelector
if in.Selector != nil {
out.Selector = new(LabelSelector)
if err := Convert_extensions_LabelSelector_To_v1beta1_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
// unable to generate simple pointer conversion for api.PodTemplateSpec -> v1.PodTemplateSpec
if in.Template != nil {
out.Template = new(v1.PodTemplateSpec)
if err := Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}
func autoConvert_extensions_ReplicaSetStatus_To_v1beta1_ReplicaSetStatus(in *extensions.ReplicaSetStatus, out *ReplicaSetStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetStatus))(in)
}
out.Replicas = int32(in.Replicas)
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func Convert_extensions_ReplicaSetStatus_To_v1beta1_ReplicaSetStatus(in *extensions.ReplicaSetStatus, out *ReplicaSetStatus, s conversion.Scope) error {
return autoConvert_extensions_ReplicaSetStatus_To_v1beta1_ReplicaSetStatus(in, out, s)
}
func autoConvert_extensions_ReplicationControllerDummy_To_v1beta1_ReplicationControllerDummy(in *extensions.ReplicationControllerDummy, out *ReplicationControllerDummy, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicationControllerDummy))(in)
@ -4397,6 +4488,95 @@ func Convert_v1beta1_NodeUtilization_To_extensions_NodeUtilization(in *NodeUtili
return autoConvert_v1beta1_NodeUtilization_To_extensions_NodeUtilization(in, out, s)
}
func autoConvert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(in *ReplicaSet, out *extensions.ReplicaSet, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicaSet))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1beta1_ReplicaSetStatus_To_extensions_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(in *ReplicaSet, out *extensions.ReplicaSet, s conversion.Scope) error {
return autoConvert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(in, out, s)
}
func autoConvert_v1beta1_ReplicaSetList_To_extensions_ReplicaSetList(in *ReplicaSetList, out *extensions.ReplicaSetList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicaSetList))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]extensions.ReplicaSet, len(in.Items))
for i := range in.Items {
if err := Convert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(&in.Items[i], &out.Items[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_v1beta1_ReplicaSetList_To_extensions_ReplicaSetList(in *ReplicaSetList, out *extensions.ReplicaSetList, s conversion.Scope) error {
return autoConvert_v1beta1_ReplicaSetList_To_extensions_ReplicaSetList(in, out, s)
}
func autoConvert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec(in *ReplicaSetSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicaSetSpec))(in)
}
// in.Replicas has no peer in out
// unable to generate simple pointer conversion for v1beta1.LabelSelector -> extensions.LabelSelector
if in.Selector != nil {
out.Selector = new(extensions.LabelSelector)
if err := Convert_v1beta1_LabelSelector_To_extensions_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
// unable to generate simple pointer conversion for v1.PodTemplateSpec -> api.PodTemplateSpec
if in.Template != nil {
out.Template = new(api.PodTemplateSpec)
if err := Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in.Template, out.Template, s); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}
func autoConvert_v1beta1_ReplicaSetStatus_To_extensions_ReplicaSetStatus(in *ReplicaSetStatus, out *extensions.ReplicaSetStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicaSetStatus))(in)
}
out.Replicas = int(in.Replicas)
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func Convert_v1beta1_ReplicaSetStatus_To_extensions_ReplicaSetStatus(in *ReplicaSetStatus, out *extensions.ReplicaSetStatus, s conversion.Scope) error {
return autoConvert_v1beta1_ReplicaSetStatus_To_extensions_ReplicaSetStatus(in, out, s)
}
func autoConvert_v1beta1_ReplicationControllerDummy_To_extensions_ReplicationControllerDummy(in *ReplicationControllerDummy, out *extensions.ReplicationControllerDummy, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicationControllerDummy))(in)
@ -4687,6 +4867,10 @@ func init() {
autoConvert_extensions_LabelSelectorRequirement_To_v1beta1_LabelSelectorRequirement,
autoConvert_extensions_LabelSelector_To_v1beta1_LabelSelector,
autoConvert_extensions_NodeUtilization_To_v1beta1_NodeUtilization,
autoConvert_extensions_ReplicaSetList_To_v1beta1_ReplicaSetList,
autoConvert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec,
autoConvert_extensions_ReplicaSetStatus_To_v1beta1_ReplicaSetStatus,
autoConvert_extensions_ReplicaSet_To_v1beta1_ReplicaSet,
autoConvert_extensions_ReplicationControllerDummy_To_v1beta1_ReplicationControllerDummy,
autoConvert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet,
autoConvert_extensions_RollingUpdateDeployment_To_v1beta1_RollingUpdateDeployment,
@ -4780,6 +4964,10 @@ func init() {
autoConvert_v1beta1_LabelSelector_To_extensions_LabelSelector,
autoConvert_v1beta1_ListOptions_To_api_ListOptions,
autoConvert_v1beta1_NodeUtilization_To_extensions_NodeUtilization,
autoConvert_v1beta1_ReplicaSetList_To_extensions_ReplicaSetList,
autoConvert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec,
autoConvert_v1beta1_ReplicaSetStatus_To_extensions_ReplicaSetStatus,
autoConvert_v1beta1_ReplicaSet_To_extensions_ReplicaSet,
autoConvert_v1beta1_ReplicationControllerDummy_To_extensions_ReplicationControllerDummy,
autoConvert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet,
autoConvert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment,

View File

@ -1592,6 +1592,74 @@ func deepCopy_v1beta1_NodeUtilization(in NodeUtilization, out *NodeUtilization,
return nil
}
func deepCopy_v1beta1_ReplicaSet(in ReplicaSet, out *ReplicaSet, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := deepCopy_v1beta1_ReplicaSetSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := deepCopy_v1beta1_ReplicaSetStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func deepCopy_v1beta1_ReplicaSetList(in ReplicaSetList, out *ReplicaSetList, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]ReplicaSet, len(in.Items))
for i := range in.Items {
if err := deepCopy_v1beta1_ReplicaSet(in.Items[i], &out.Items[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func deepCopy_v1beta1_ReplicaSetSpec(in ReplicaSetSpec, out *ReplicaSetSpec, c *conversion.Cloner) error {
if in.Replicas != nil {
out.Replicas = new(int32)
*out.Replicas = *in.Replicas
} else {
out.Replicas = nil
}
if in.Selector != nil {
out.Selector = new(LabelSelector)
if err := deepCopy_v1beta1_LabelSelector(*in.Selector, out.Selector, c); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.Template != nil {
out.Template = new(v1.PodTemplateSpec)
if err := deepCopy_v1_PodTemplateSpec(*in.Template, out.Template, c); err != nil {
return err
}
} else {
out.Template = nil
}
return nil
}
func deepCopy_v1beta1_ReplicaSetStatus(in ReplicaSetStatus, out *ReplicaSetStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func deepCopy_v1beta1_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
@ -1851,6 +1919,10 @@ func init() {
deepCopy_v1beta1_LabelSelectorRequirement,
deepCopy_v1beta1_ListOptions,
deepCopy_v1beta1_NodeUtilization,
deepCopy_v1beta1_ReplicaSet,
deepCopy_v1beta1_ReplicaSetList,
deepCopy_v1beta1_ReplicaSetSpec,
deepCopy_v1beta1_ReplicaSetStatus,
deepCopy_v1beta1_ReplicationControllerDummy,
deepCopy_v1beta1_RollingUpdateDaemonSet,
deepCopy_v1beta1_RollingUpdateDeployment,

View File

@ -142,5 +142,26 @@ func addDefaultingFuncs(scheme *runtime.Scheme) {
obj.Data = make(map[string]string)
}
},
func(obj *ReplicaSet) {
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 obj.Spec.Selector == nil {
obj.Spec.Selector = &LabelSelector{
MatchLabels: labels,
}
}
if len(obj.Labels) == 0 {
obj.Labels = labels
}
}
if obj.Spec.Replicas == nil {
obj.Spec.Replicas = new(int32)
*obj.Spec.Replicas = 1
}
},
)
}

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/api"
_ "k8s.io/kubernetes/pkg/api/install"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/v1"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
. "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
@ -373,6 +374,219 @@ func TestSetDefaultJob(t *testing.T) {
}
}
func TestSetDefaultReplicaSet(t *testing.T) {
tests := []struct {
rs *ReplicaSet
expectLabels bool
expectSelector bool
}{
{
rs: &ReplicaSet{
Spec: ReplicaSetSpec{
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: true,
expectSelector: true,
},
{
rs: &ReplicaSet{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"bar": "foo",
},
},
Spec: ReplicaSetSpec{
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: false,
expectSelector: true,
},
{
rs: &ReplicaSet{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"bar": "foo",
},
},
Spec: ReplicaSetSpec{
Selector: &LabelSelector{
MatchLabels: map[string]string{
"some": "other",
},
},
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: false,
expectSelector: false,
},
{
rs: &ReplicaSet{
Spec: ReplicaSetSpec{
Selector: &LabelSelector{
MatchLabels: map[string]string{
"some": "other",
},
},
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: true,
expectSelector: false,
},
}
for _, test := range tests {
rs := test.rs
obj2 := roundTrip(t, runtime.Object(rs))
rs2, ok := obj2.(*ReplicaSet)
if !ok {
t.Errorf("unexpected object: %v", rs2)
t.FailNow()
}
if test.expectSelector != reflect.DeepEqual(rs2.Spec.Selector.MatchLabels, rs2.Spec.Template.Labels) {
if test.expectSelector {
t.Errorf("expected: %v, got: %v", rs2.Spec.Template.Labels, rs2.Spec.Selector)
} else {
t.Errorf("unexpected equality: %v", rs.Spec.Selector)
}
}
if test.expectLabels != reflect.DeepEqual(rs2.Labels, rs2.Spec.Template.Labels) {
if test.expectLabels {
t.Errorf("expected: %v, got: %v", rs2.Spec.Template.Labels, rs2.Labels)
} else {
t.Errorf("unexpected equality: %v", rs.Labels)
}
}
}
}
func TestSetDefaultReplicaSetReplicas(t *testing.T) {
tests := []struct {
rs ReplicaSet
expectReplicas int32
}{
{
rs: ReplicaSet{
Spec: ReplicaSetSpec{
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 1,
},
{
rs: ReplicaSet{
Spec: ReplicaSetSpec{
Replicas: newInt32(0),
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 0,
},
{
rs: ReplicaSet{
Spec: ReplicaSetSpec{
Replicas: newInt32(3),
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 3,
},
}
for _, test := range tests {
rs := &test.rs
obj2 := roundTrip(t, runtime.Object(rs))
rs2, ok := obj2.(*ReplicaSet)
if !ok {
t.Errorf("unexpected object: %v", rs2)
t.FailNow()
}
if rs2.Spec.Replicas == nil {
t.Errorf("unexpected nil Replicas")
} else if test.expectReplicas != *rs2.Spec.Replicas {
t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rs2.Spec.Replicas)
}
}
}
func TestDefaultRequestIsNotSetForReplicaSet(t *testing.T) {
s := v1.PodSpec{}
s.Containers = []v1.Container{
{
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
},
},
},
}
rs := &ReplicaSet{
Spec: ReplicaSetSpec{
Replicas: newInt32(3),
Template: &v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
Spec: s,
},
},
}
output := roundTrip(t, runtime.Object(rs))
rs2 := output.(*ReplicaSet)
defaultRequest := rs2.Spec.Template.Spec.Containers[0].Resources.Requests
requestValue := defaultRequest[v1.ResourceCPU]
if requestValue.String() != "0" {
t.Errorf("Expected 0 request value, got: %s", requestValue.String())
}
}
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
data, err := runtime.Encode(Codec, obj)
if err != nil {

View File

@ -62,6 +62,8 @@ func addKnownTypes(scheme *runtime.Scheme) {
&ConfigMap{},
&ConfigMapList{},
&v1.DeleteOptions{},
&ReplicaSet{},
&ReplicaSetList{},
)
}
@ -86,3 +88,5 @@ func (obj *IngressList) GetObjectKind() unversioned.ObjectKind {
func (obj *ListOptions) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ConfigMap) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ConfigMapList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ReplicaSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ReplicaSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

File diff suppressed because it is too large Load Diff

View File

@ -819,3 +819,66 @@ type ConfigMapList struct {
// Items is the list of ConfigMaps.
Items []ConfigMap `json:"items,omitempty"`
}
// ReplicaSet represents the configuration of a ReplicaSet.
type ReplicaSet struct {
unversioned.TypeMeta `json:",inline"`
// If the Labels of a ReplicaSet are empty, they are defaulted to
// be the same as the Pod(s) that the ReplicaSet manages.
// Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
v1.ObjectMeta `json:"metadata,omitempty"`
// Spec defines the specification of the desired behavior of the ReplicaSet.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
Spec ReplicaSetSpec `json:"spec,omitempty"`
// Status is the most recently observed status of the ReplicaSet.
// This data may be out of date by some window of time.
// Populated by the system.
// Read-only.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
Status ReplicaSetStatus `json:"status,omitempty"`
}
// ReplicaSetList is a collection of ReplicaSets.
type ReplicaSetList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
unversioned.ListMeta `json:"metadata,omitempty"`
// List of ReplicaSets.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md
Items []ReplicaSet `json:"items"`
}
// ReplicaSetSpec is the specification of a ReplicaSet.
type ReplicaSetSpec struct {
// Replicas is the number of desired replicas.
// This is a pointer to distinguish between explicit zero and unspecified.
// Defaults to 1.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller
Replicas *int32 `json:"replicas,omitempty"`
// Selector is a label query over pods that should match the replica count.
// If the selector is empty, it is defaulted to the labels present on the pod template.
// Label keys and values that must match in order to be controlled by this replica set.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
Selector *LabelSelector `json:"selector,omitempty"`
// Template is the object that describes the pod that will be created if
// insufficient replicas are detected.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#pod-template
Template *v1.PodTemplateSpec `json:"template,omitempty"`
}
// ReplicaSetStatus represents the current status of a ReplicaSet.
type ReplicaSetStatus struct {
// Replicas is the most recently oberved number of replicas.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller
Replicas int32 `json:"replicas"`
// ObservedGeneration reflects the generation of the most recently observed ReplicaSet.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

View File

@ -448,6 +448,48 @@ func (NodeUtilization) SwaggerDoc() map[string]string {
return map_NodeUtilization
}
var map_ReplicaSet = map[string]string{
"": "ReplicaSet represents the configuration of a ReplicaSet.",
"metadata": "If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the specification of the desired behavior of the ReplicaSet. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Status is the most recently observed status of the ReplicaSet. This data may be out of date by some window of time. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
}
func (ReplicaSet) SwaggerDoc() map[string]string {
return map_ReplicaSet
}
var map_ReplicaSetList = map[string]string{
"": "ReplicaSetList is a collection of ReplicaSets.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "List of ReplicaSets. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md",
}
func (ReplicaSetList) SwaggerDoc() map[string]string {
return map_ReplicaSetList
}
var map_ReplicaSetSpec = map[string]string{
"": "ReplicaSetSpec is the specification of a ReplicaSet.",
"replicas": "Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"selector": "Selector is a label query over pods that should match the replica count. If the selector is empty, it is defaulted to the labels present on the pod template. Label keys and values that must match in order to be controlled by this replica set. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
"template": "Template is the object that describes the pod that will be created if insufficient replicas are detected. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#pod-template",
}
func (ReplicaSetSpec) SwaggerDoc() map[string]string {
return map_ReplicaSetSpec
}
var map_ReplicaSetStatus = map[string]string{
"": "ReplicaSetStatus represents the current status of a ReplicaSet.",
"replicas": "Replicas is the most recently oberved number of replicas. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"observedGeneration": "ObservedGeneration reflects the generation of the most recently observed ReplicaSet.",
}
func (ReplicaSetStatus) SwaggerDoc() map[string]string {
return map_ReplicaSetStatus
}
var map_ReplicationControllerDummy = map[string]string{
"": "Dummy definition",
}

View File

@ -655,6 +655,86 @@ func ValidateConfigMapUpdate(newCfg, oldCfg *extensions.ConfigMap) field.ErrorLi
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...)
allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
return allErrs
}
// ValidateReplicaSetName can be used to check whether the given ReplicaSet
// name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateReplicaSetName(name string, prefix bool) (bool, string) {
return apivalidation.NameIsDNSSubdomain(name, prefix)
}
// ValidateReplicaSet tests if required fields in the ReplicaSet are set.
func ValidateReplicaSet(rs *extensions.ReplicaSet) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&rs.ObjectMeta, true, ValidateReplicaSetName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateReplicaSetSpec(&rs.Spec, field.NewPath("spec"))...)
return allErrs
}
// ValidateReplicaSetUpdate tests if required fields in the ReplicaSet are set.
func ValidateReplicaSetUpdate(rs, oldRs *extensions.ReplicaSet) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&rs.ObjectMeta, &oldRs.ObjectMeta, field.NewPath("metadata"))...)
allErrs = append(allErrs, ValidateReplicaSetSpec(&rs.Spec, field.NewPath("spec"))...)
return allErrs
}
// ValidateReplicaSetStatusUpdate tests if required fields in the ReplicaSet are set.
func ValidateReplicaSetStatusUpdate(rs, oldRs *extensions.ReplicaSet) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&rs.ObjectMeta, &oldRs.ObjectMeta, field.NewPath("metadata"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(rs.Status.Replicas), field.NewPath("status", "replicas"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(rs.Status.ObservedGeneration), field.NewPath("status", "observedGeneration"))...)
return allErrs
}
// ValidateReplicaSetSpec tests if required fields in the ReplicaSet spec are set.
func ValidateReplicaSetSpec(spec *extensions.ReplicaSetSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
if spec.Selector == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("selector"), ""))
} else {
allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for deployment."))
}
}
selector, err := extensions.LabelSelectorAsSelector(spec.Selector)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "failed to convert LabelSelector to Selector."))
} else {
allErrs = append(allErrs, ValidatePodTemplateSpecForReplicaSet(spec.Template, selector, spec.Replicas, fldPath.Child("template"))...)
}
return allErrs
}
// Validates the given template and ensures that it is in accordance with the desired selector and replicas.
func ValidatePodTemplateSpecForReplicaSet(template *api.PodTemplateSpec, selector labels.Selector, replicas int, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if template == nil {
allErrs = append(allErrs, field.Required(fldPath, ""))
} else {
if !selector.Empty() {
// Verify that the ReplicaSet selector matches the labels in template.
labels := labels.Set(template.Labels)
if !selector.Matches(labels) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`"))
}
}
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(template, fldPath)...)
if replicas > 1 {
allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(template.Spec.Volumes, fldPath.Child("spec", "volumes"))...)
}
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
if template.Spec.RestartPolicy != api.RestartPolicyAlways {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
}
}
return allErrs
}

View File

@ -1458,12 +1458,6 @@ func TestValidateScale(t *testing.T) {
}
}
func newInt(val int) *int {
p := new(int)
*p = val
return p
}
func TestValidateConfigMap(t *testing.T) {
newConfigMap := func(name, namespace string, data map[string]string) extensions.ConfigMap {
return extensions.ConfigMap{
@ -1565,3 +1559,474 @@ func TestValidateConfigMapUpdate(t *testing.T) {
}
}
}
func TestValidateReplicaSetStatusUpdate(t *testing.T) {
validLabels := map[string]string{"a": "b"}
validPodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
}
type rcUpdateTest struct {
old extensions.ReplicaSet
update extensions.ReplicaSet
}
successCases := []rcUpdateTest{
{
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
Status: extensions.ReplicaSetStatus{
Replicas: 2,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 3,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
Status: extensions.ReplicaSetStatus{
Replicas: 4,
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateReplicaSetStatusUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]rcUpdateTest{
"negative replicas": {
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
Status: extensions.ReplicaSetStatus{
Replicas: 3,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 2,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
Status: extensions.ReplicaSetStatus{
Replicas: -3,
},
},
},
}
for testName, errorCase := range errorCases {
if errs := ValidateReplicaSetStatusUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
}
}
}
func TestValidateReplicaSetUpdate(t *testing.T) {
validLabels := map[string]string{"a": "b"}
validPodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
}
readWriteVolumePodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
},
},
}
invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
invalidPodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
ObjectMeta: api.ObjectMeta{
Labels: invalidLabels,
},
},
}
type rcUpdateTest struct {
old extensions.ReplicaSet
update extensions.ReplicaSet
}
successCases := []rcUpdateTest{
{
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 3,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
},
{
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 1,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &readWriteVolumePodTemplate.Template,
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateReplicaSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]rcUpdateTest{
"more than one read/write": {
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 2,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &readWriteVolumePodTemplate.Template,
},
},
},
"invalid selector": {
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 2,
Selector: &extensions.LabelSelector{MatchLabels: invalidLabels},
Template: &validPodTemplate.Template,
},
},
},
"invalid pod": {
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 2,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &invalidPodTemplate.Template,
},
},
},
"negative replicas": {
old: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
update: extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: -1,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
},
}
for testName, errorCase := range errorCases {
if errs := ValidateReplicaSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
}
}
}
func TestValidateReplicaSet(t *testing.T) {
validLabels := map[string]string{"a": "b"}
validPodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
}
readWriteVolumePodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
Spec: api.PodSpec{
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
}
invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
invalidPodTemplate := api.PodTemplate{
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
ObjectMeta: api.ObjectMeta{
Labels: invalidLabels,
},
},
}
successCases := []extensions.ReplicaSet{
{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
{
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
{
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: 1,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &readWriteVolumePodTemplate.Template,
},
},
}
for _, successCase := range successCases {
if errs := ValidateReplicaSet(&successCase); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]extensions.ReplicaSet{
"zero-length ID": {
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
"missing-namespace": {
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
"empty selector": {
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Template: &validPodTemplate.Template,
},
},
"selector_doesnt_match": {
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
Template: &validPodTemplate.Template,
},
},
"invalid manifest": {
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
},
},
"read-write persistent disk with > 1 pod": {
ObjectMeta: api.ObjectMeta{Name: "abc"},
Spec: extensions.ReplicaSetSpec{
Replicas: 2,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &readWriteVolumePodTemplate.Template,
},
},
"negative_replicas": {
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Spec: extensions.ReplicaSetSpec{
Replicas: -1,
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
},
},
"invalid_label": {
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Namespace: api.NamespaceDefault,
Labels: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
"invalid_label 2": {
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Namespace: api.NamespaceDefault,
Labels: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: extensions.ReplicaSetSpec{
Template: &invalidPodTemplate.Template,
},
},
"invalid_annotation": {
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Namespace: api.NamespaceDefault,
Annotations: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &validPodTemplate.Template,
},
},
"invalid restart policy 1": {
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Namespace: api.NamespaceDefault,
},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &api.PodTemplateSpec{
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
},
},
},
"invalid restart policy 2": {
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Namespace: api.NamespaceDefault,
},
Spec: extensions.ReplicaSetSpec{
Selector: &extensions.LabelSelector{MatchLabels: validLabels},
Template: &api.PodTemplateSpec{
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyNever,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
ObjectMeta: api.ObjectMeta{
Labels: validLabels,
},
},
},
},
}
for k, v := range errorCases {
errs := ValidateReplicaSet(&v)
if len(errs) == 0 {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
field := errs[i].Field
if !strings.HasPrefix(field, "spec.template.") &&
field != "metadata.name" &&
field != "metadata.namespace" &&
field != "spec.selector" &&
field != "spec.template" &&
field != "GCEPersistentDisk.ReadOnly" &&
field != "spec.replicas" &&
field != "spec.template.labels" &&
field != "metadata.annotations" &&
field != "metadata.labels" &&
field != "status.replicas" {
t.Errorf("%s: missing prefix for: %v", k, errs[i])
}
}
}
}
func newInt(val int) *int {
p := new(int)
*p = val
return p
}