mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
Add a limit range resource
This commit is contained in:
parent
358ace610d
commit
091cbe5fa2
@ -47,6 +47,8 @@ func init() {
|
|||||||
&BoundPod{},
|
&BoundPod{},
|
||||||
&BoundPods{},
|
&BoundPods{},
|
||||||
&List{},
|
&List{},
|
||||||
|
&LimitRange{},
|
||||||
|
&LimitRangeList{},
|
||||||
)
|
)
|
||||||
// Legacy names are supported
|
// Legacy names are supported
|
||||||
Scheme.AddKnownTypeWithName("", "Minion", &Node{})
|
Scheme.AddKnownTypeWithName("", "Minion", &Node{})
|
||||||
@ -77,3 +79,5 @@ func (*ContainerManifestList) IsAnAPIObject() {}
|
|||||||
func (*BoundPod) IsAnAPIObject() {}
|
func (*BoundPod) IsAnAPIObject() {}
|
||||||
func (*BoundPods) IsAnAPIObject() {}
|
func (*BoundPods) IsAnAPIObject() {}
|
||||||
func (*List) IsAnAPIObject() {}
|
func (*List) IsAnAPIObject() {}
|
||||||
|
func (*LimitRange) IsAnAPIObject() {}
|
||||||
|
func (*LimitRangeList) IsAnAPIObject() {}
|
||||||
|
@ -1138,3 +1138,37 @@ type List struct {
|
|||||||
|
|
||||||
Items []runtime.Object `json:"items"`
|
Items []runtime.Object `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitRangeItem defines a min/max usage limit for any resource that matches on kind
|
||||||
|
type LimitRangeItem struct {
|
||||||
|
// Kind is the resource kind that this limit range is applied (i.e. pods, etc.)
|
||||||
|
Kind string
|
||||||
|
// Max usage constraints on this kind by resource name
|
||||||
|
Max ResourceList `json:"max,omitempty"`
|
||||||
|
// Min usage constraints on this kind by resource name
|
||||||
|
Min ResourceList `json:"min,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRange sets resource usage limits for each kind of resource in a Namespace
|
||||||
|
type LimitRange struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Spec defines the limits enforced
|
||||||
|
Spec LimitRangeSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRangeList is a list of LimitRange items.
|
||||||
|
type LimitRangeList struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
ListMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Items is a list of LimitRange objects
|
||||||
|
Items []LimitRange `json:"items"`
|
||||||
|
}
|
||||||
|
@ -568,7 +568,72 @@ func init() {
|
|||||||
out.Status.HostIP = in.HostIP
|
out.Status.HostIP = in.HostIP
|
||||||
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
|
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
|
||||||
},
|
},
|
||||||
|
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.TypeMeta, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Spec, &out.Spec, 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.TypeMeta, &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.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error {
|
||||||
|
*out = LimitRangeSpec{}
|
||||||
|
out.Limits = make([]LimitRangeItem, len(in.Limits), 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 *LimitRangeSpec, out *newer.LimitRangeSpec, s conversion.Scope) error {
|
||||||
|
*out = newer.LimitRangeSpec{}
|
||||||
|
out.Limits = make([]newer.LimitRangeItem, len(in.Limits), 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.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error {
|
||||||
|
*out = LimitRangeItem{}
|
||||||
|
out.Kind = in.Kind
|
||||||
|
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *LimitRangeItem, out *newer.LimitRangeItem, s conversion.Scope) error {
|
||||||
|
*out = newer.LimitRangeItem{}
|
||||||
|
out.Kind = in.Kind
|
||||||
|
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
// Object ID <-> Name
|
// Object ID <-> Name
|
||||||
// TODO: amend the conversion package to allow overriding specific fields.
|
// TODO: amend the conversion package to allow overriding specific fields.
|
||||||
func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error {
|
func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error {
|
||||||
|
@ -48,6 +48,8 @@ func init() {
|
|||||||
&BoundPod{},
|
&BoundPod{},
|
||||||
&BoundPods{},
|
&BoundPods{},
|
||||||
&List{},
|
&List{},
|
||||||
|
&LimitRange{},
|
||||||
|
&LimitRangeList{},
|
||||||
)
|
)
|
||||||
// Future names are supported
|
// Future names are supported
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
|
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
|
||||||
@ -78,3 +80,5 @@ func (*ContainerManifestList) IsAnAPIObject() {}
|
|||||||
func (*BoundPod) IsAnAPIObject() {}
|
func (*BoundPod) IsAnAPIObject() {}
|
||||||
func (*BoundPods) IsAnAPIObject() {}
|
func (*BoundPods) IsAnAPIObject() {}
|
||||||
func (*List) IsAnAPIObject() {}
|
func (*List) IsAnAPIObject() {}
|
||||||
|
func (*LimitRange) IsAnAPIObject() {}
|
||||||
|
func (*LimitRangeList) IsAnAPIObject() {}
|
||||||
|
@ -904,3 +904,35 @@ type List struct {
|
|||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitRangeItem defines a min/max usage limit for any resource that matches on kind
|
||||||
|
type LimitRangeItem struct {
|
||||||
|
// Kind is the resource kind that this limit range is applied (i.e. pods, etc.)
|
||||||
|
Kind string
|
||||||
|
// Max usage constraints on this kind by resource name
|
||||||
|
Max ResourceList `json:"max,omitempty"`
|
||||||
|
// Min usage constraints on this kind by resource name
|
||||||
|
Min ResourceList `json:"min,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRange sets resource usage limits for each kind of resource in a Namespace
|
||||||
|
type LimitRange struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// Spec defines the limits enforced
|
||||||
|
Spec LimitRangeSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRangeList is a list of LimitRange items.
|
||||||
|
type LimitRangeList struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// Items is a list of LimitRange objects
|
||||||
|
Items []LimitRange `json:"items"`
|
||||||
|
}
|
||||||
|
@ -485,7 +485,72 @@ func init() {
|
|||||||
out.Status.HostIP = in.HostIP
|
out.Status.HostIP = in.HostIP
|
||||||
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
|
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
|
||||||
},
|
},
|
||||||
|
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.TypeMeta, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Spec, &out.Spec, 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.TypeMeta, &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.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error {
|
||||||
|
*out = LimitRangeSpec{}
|
||||||
|
out.Limits = make([]LimitRangeItem, len(in.Limits), 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 *LimitRangeSpec, out *newer.LimitRangeSpec, s conversion.Scope) error {
|
||||||
|
*out = newer.LimitRangeSpec{}
|
||||||
|
out.Limits = make([]newer.LimitRangeItem, len(in.Limits), 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.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error {
|
||||||
|
*out = LimitRangeItem{}
|
||||||
|
out.Kind = in.Kind
|
||||||
|
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *LimitRangeItem, out *newer.LimitRangeItem, s conversion.Scope) error {
|
||||||
|
*out = newer.LimitRangeItem{}
|
||||||
|
out.Kind = in.Kind
|
||||||
|
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
// Object ID <-> Name
|
// Object ID <-> Name
|
||||||
// TODO: amend the conversion package to allow overriding specific fields.
|
// TODO: amend the conversion package to allow overriding specific fields.
|
||||||
func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error {
|
func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error {
|
||||||
|
@ -48,6 +48,8 @@ func init() {
|
|||||||
&BoundPod{},
|
&BoundPod{},
|
||||||
&BoundPods{},
|
&BoundPods{},
|
||||||
&List{},
|
&List{},
|
||||||
|
&LimitRange{},
|
||||||
|
&LimitRangeList{},
|
||||||
)
|
)
|
||||||
// Future names are supported
|
// Future names are supported
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
|
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
|
||||||
@ -78,3 +80,5 @@ func (*ContainerManifestList) IsAnAPIObject() {}
|
|||||||
func (*BoundPod) IsAnAPIObject() {}
|
func (*BoundPod) IsAnAPIObject() {}
|
||||||
func (*BoundPods) IsAnAPIObject() {}
|
func (*BoundPods) IsAnAPIObject() {}
|
||||||
func (*List) IsAnAPIObject() {}
|
func (*List) IsAnAPIObject() {}
|
||||||
|
func (*LimitRange) IsAnAPIObject() {}
|
||||||
|
func (*LimitRangeList) IsAnAPIObject() {}
|
||||||
|
@ -906,3 +906,35 @@ type List struct {
|
|||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitRangeItem defines a min/max usage limit for any resource that matches on kind
|
||||||
|
type LimitRangeItem struct {
|
||||||
|
// Kind is the resource kind that this limit range is applied (i.e. pods, etc.)
|
||||||
|
Kind string
|
||||||
|
// Max usage constraints on this kind by resource name
|
||||||
|
Max ResourceList `json:"max,omitempty"`
|
||||||
|
// Min usage constraints on this kind by resource name
|
||||||
|
Min ResourceList `json:"min,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRange sets resource usage limits for each kind of resource in a Namespace
|
||||||
|
type LimitRange struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// Spec defines the limits enforced
|
||||||
|
Spec LimitRangeSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRangeList is a list of LimitRange items.
|
||||||
|
type LimitRangeList struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// Items is a list of LimitRange objects
|
||||||
|
Items []LimitRange `json:"items"`
|
||||||
|
}
|
||||||
|
@ -48,6 +48,8 @@ func init() {
|
|||||||
&Event{},
|
&Event{},
|
||||||
&EventList{},
|
&EventList{},
|
||||||
&List{},
|
&List{},
|
||||||
|
&LimitRange{},
|
||||||
|
&LimitRangeList{},
|
||||||
)
|
)
|
||||||
// Legacy names are supported
|
// Legacy names are supported
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
|
api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
|
||||||
@ -78,3 +80,5 @@ func (*OperationList) IsAnAPIObject() {}
|
|||||||
func (*Event) IsAnAPIObject() {}
|
func (*Event) IsAnAPIObject() {}
|
||||||
func (*EventList) IsAnAPIObject() {}
|
func (*EventList) IsAnAPIObject() {}
|
||||||
func (*List) IsAnAPIObject() {}
|
func (*List) IsAnAPIObject() {}
|
||||||
|
func (*LimitRange) IsAnAPIObject() {}
|
||||||
|
func (*LimitRangeList) IsAnAPIObject() {}
|
||||||
|
@ -1066,3 +1066,37 @@ type List struct {
|
|||||||
|
|
||||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitRangeItem defines a min/max usage limit for any resource that matches on kind
|
||||||
|
type LimitRangeItem struct {
|
||||||
|
// Kind is the resource kind that this limit range is applied (i.e. pods, etc.)
|
||||||
|
Kind string
|
||||||
|
// Max usage constraints on this kind by resource name
|
||||||
|
Max ResourceList `json:"max,omitempty"`
|
||||||
|
// Min usage constraints on this kind by resource name
|
||||||
|
Min ResourceList `json:"min,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRange sets resource usage limits for each kind of resource in a Namespace
|
||||||
|
type LimitRange struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Spec defines the limits enforced
|
||||||
|
Spec LimitRangeSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRangeList is a list of LimitRange items.
|
||||||
|
type LimitRangeList struct {
|
||||||
|
TypeMeta `json:",inline"`
|
||||||
|
ListMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Items is a list of LimitRange objects
|
||||||
|
Items []LimitRange `json:"items"`
|
||||||
|
}
|
||||||
|
@ -640,3 +640,29 @@ func ValidateResourceName(str string) errs.ValidationErrorList {
|
|||||||
|
|
||||||
return errs.ValidationErrorList{}
|
return errs.ValidationErrorList{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateLimitRange tests if required fields in the LimitRange are set.
|
||||||
|
func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
if len(limitRange.Name) == 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("name", limitRange.Name))
|
||||||
|
} else if !util.IsDNSSubdomain(limitRange.Name) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("name", limitRange.Name, ""))
|
||||||
|
}
|
||||||
|
if len(limitRange.Namespace) == 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("namespace", limitRange.Namespace))
|
||||||
|
} else if !util.IsDNSSubdomain(limitRange.Namespace) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", limitRange.Namespace, ""))
|
||||||
|
}
|
||||||
|
// ensure resource names are properly qualified per docs/resources.md
|
||||||
|
for i := range limitRange.Spec.Limits {
|
||||||
|
limit := limitRange.Spec.Limits[i]
|
||||||
|
for k, _ := range limit.Max {
|
||||||
|
allErrs = append(allErrs, ValidateResourceName(k))
|
||||||
|
}
|
||||||
|
for k, _ := range limit.Min {
|
||||||
|
allErrs = append(allErrs, ValidateResourceName(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@ -1552,3 +1552,92 @@ func TestValidateResourceNames(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateLimitRange(t *testing.T) {
|
||||||
|
successCases := []api.LimitRange{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
Namespace: "foo",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, successCase := range successCases {
|
||||||
|
if errs := ValidateLimitRange(&successCase); len(errs) != 0 {
|
||||||
|
t.Errorf("expected success: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCases := map[string]api.LimitRange{
|
||||||
|
"zero-length Name": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "",
|
||||||
|
Namespace: "foo",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"zero-length-namespace": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
Namespace: "",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for k, v := range errorCases {
|
||||||
|
errs := ValidateLimitRange(&v)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure for %s", k)
|
||||||
|
}
|
||||||
|
for i := range errs {
|
||||||
|
field := errs[i].(*errors.ValidationError).Field
|
||||||
|
if field != "name" &&
|
||||||
|
field != "namespace" {
|
||||||
|
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ type Interface interface {
|
|||||||
VersionInterface
|
VersionInterface
|
||||||
NodesInterface
|
NodesInterface
|
||||||
EventNamespacer
|
EventNamespacer
|
||||||
|
LimitRangesNamespacer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
||||||
@ -63,6 +64,10 @@ func (c *Client) Services(namespace string) ServiceInterface {
|
|||||||
return newServices(c, namespace)
|
return newServices(c, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) LimitRanges(namespace string) LimitRangeInterface {
|
||||||
|
return newLimitRanges(c, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// VersionInterface has a method to retrieve the server version.
|
// VersionInterface has a method to retrieve the server version.
|
||||||
type VersionInterface interface {
|
type VersionInterface interface {
|
||||||
ServerVersion() (*version.Info, error)
|
ServerVersion() (*version.Info, error)
|
||||||
|
@ -34,15 +34,20 @@ type FakeAction struct {
|
|||||||
// Fake implements Interface. Meant to be embedded into a struct to get a default
|
// Fake implements Interface. Meant to be embedded into a struct to get a default
|
||||||
// implementation. This makes faking out just the method you want to test easier.
|
// implementation. This makes faking out just the method you want to test easier.
|
||||||
type Fake struct {
|
type Fake struct {
|
||||||
Actions []FakeAction
|
Actions []FakeAction
|
||||||
PodsList api.PodList
|
PodsList api.PodList
|
||||||
Ctrl api.ReplicationController
|
Ctrl api.ReplicationController
|
||||||
ServiceList api.ServiceList
|
ServiceList api.ServiceList
|
||||||
EndpointsList api.EndpointsList
|
EndpointsList api.EndpointsList
|
||||||
MinionsList api.NodeList
|
MinionsList api.NodeList
|
||||||
EventsList api.EventList
|
EventsList api.EventList
|
||||||
Err error
|
LimitRangesList api.LimitRangeList
|
||||||
Watch watch.Interface
|
Err error
|
||||||
|
Watch watch.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Fake) LimitRanges(namespace string) LimitRangeInterface {
|
||||||
|
return &FakeLimitRanges{Fake: c, Namespace: namespace}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Fake) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
func (c *Fake) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
||||||
|
54
pkg/client/fake_limit_ranges.go
Normal file
54
pkg/client/fake_limit_ranges.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FakeLimitRanges implements PodsInterface. Meant to be embedded into a struct to get a default
|
||||||
|
// implementation. This makes faking out just the methods you want to test easier.
|
||||||
|
type FakeLimitRanges struct {
|
||||||
|
Fake *Fake
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeLimitRanges) List(selector labels.Selector) (*api.LimitRangeList, error) {
|
||||||
|
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "list-limitRanges"})
|
||||||
|
return api.Scheme.CopyOrDie(&c.Fake.LimitRangesList).(*api.LimitRangeList), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeLimitRanges) Get(name string) (*api.LimitRange, error) {
|
||||||
|
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "get-limitRange", Value: name})
|
||||||
|
return &api.LimitRange{ObjectMeta: api.ObjectMeta{Name: name, Namespace: c.Namespace}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeLimitRanges) Delete(name string) error {
|
||||||
|
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "delete-limitRange", Value: name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeLimitRanges) Create(limitRange *api.LimitRange) (*api.LimitRange, error) {
|
||||||
|
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "create-limitRange"})
|
||||||
|
return &api.LimitRange{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeLimitRanges) Update(limitRange *api.LimitRange) (*api.LimitRange, error) {
|
||||||
|
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "update-limitRange", Value: limitRange.Name})
|
||||||
|
return &api.LimitRange{}, nil
|
||||||
|
}
|
94
pkg/client/limit_ranges.go
Normal file
94
pkg/client/limit_ranges.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LimitRangesNamespacer has methods to work with LimitRange resources in a namespace
|
||||||
|
type LimitRangesNamespacer interface {
|
||||||
|
LimitRanges(namespace string) LimitRangeInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// LimitRangeInterface has methods to work with LimitRange resources.
|
||||||
|
type LimitRangeInterface interface {
|
||||||
|
List(selector labels.Selector) (*api.LimitRangeList, error)
|
||||||
|
Get(name string) (*api.LimitRange, error)
|
||||||
|
Delete(name string) error
|
||||||
|
Create(limitRange *api.LimitRange) (*api.LimitRange, error)
|
||||||
|
Update(limitRange *api.LimitRange) (*api.LimitRange, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// limitRanges implements LimitRangesNamespacer interface
|
||||||
|
type limitRanges struct {
|
||||||
|
r *Client
|
||||||
|
ns string
|
||||||
|
}
|
||||||
|
|
||||||
|
// newLimitRanges returns a limitRanges
|
||||||
|
func newLimitRanges(c *Client, namespace string) *limitRanges {
|
||||||
|
return &limitRanges{
|
||||||
|
r: c,
|
||||||
|
ns: namespace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List takes a selector, and returns the list of limitRanges that match that selector.
|
||||||
|
func (c *limitRanges) List(selector labels.Selector) (result *api.LimitRangeList, err error) {
|
||||||
|
result = &api.LimitRangeList{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("limitRanges").SelectorParam("labels", selector).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get takes the name of the limitRange, and returns the corresponding Pod object, and an error if it occurs
|
||||||
|
func (c *limitRanges) Get(name string) (result *api.LimitRange, err error) {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return nil, errors.New("name is required parameter to Get")
|
||||||
|
}
|
||||||
|
|
||||||
|
result = &api.LimitRange{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("limitRanges").Name(name).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete takes the name of the limitRange, and returns an error if one occurs
|
||||||
|
func (c *limitRanges) Delete(name string) error {
|
||||||
|
return c.r.Delete().Namespace(c.ns).Resource("limitRanges").Name(name).Do().Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create takes the representation of a limitRange. Returns the server's representation of the limitRange, and an error, if it occurs.
|
||||||
|
func (c *limitRanges) Create(limitRange *api.LimitRange) (result *api.LimitRange, err error) {
|
||||||
|
result = &api.LimitRange{}
|
||||||
|
err = c.r.Post().Namespace(c.ns).Resource("limitRanges").Body(limitRange).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update takes the representation of a limitRange to update. Returns the server's representation of the limitRange, and an error, if it occurs.
|
||||||
|
func (c *limitRanges) Update(limitRange *api.LimitRange) (result *api.LimitRange, err error) {
|
||||||
|
result = &api.LimitRange{}
|
||||||
|
if len(limitRange.ResourceVersion) == 0 {
|
||||||
|
err = fmt.Errorf("invalid update object, missing resource version: %v", limitRange)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = c.r.Put().Namespace(c.ns).Resource("limitRanges").Name(limitRange.Name).Body(limitRange).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
194
pkg/client/limit_ranges_test.go
Normal file
194
pkg/client/limit_ranges_test.go
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
//"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLimitRangeCreate(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
limitRange := &api.LimitRange{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "POST",
|
||||||
|
Path: buildResourcePath(ns, "/limitRanges"),
|
||||||
|
Query: buildQueryValues(ns, nil),
|
||||||
|
Body: limitRange,
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200, Body: limitRange},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := c.Setup().LimitRanges(ns).Create(limitRange)
|
||||||
|
c.Validate(t, response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRangeGet(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
limitRange := &api.LimitRange{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: buildResourcePath(ns, "/limitRanges/abc"),
|
||||||
|
Query: buildQueryValues(ns, nil),
|
||||||
|
Body: nil,
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200, Body: limitRange},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := c.Setup().LimitRanges(ns).Get("abc")
|
||||||
|
c.Validate(t, response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRangeList(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
|
||||||
|
limitRangeList := &api.LimitRangeList{
|
||||||
|
Items: []api.LimitRange{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: buildResourcePath(ns, "/limitRanges"),
|
||||||
|
Query: buildQueryValues(ns, nil),
|
||||||
|
Body: nil,
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200, Body: limitRangeList},
|
||||||
|
}
|
||||||
|
response, err := c.Setup().LimitRanges(ns).List(labels.Everything())
|
||||||
|
c.Validate(t, response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRangeUpdate(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
limitRange := &api.LimitRange{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{Method: "PUT", Path: buildResourcePath(ns, "/limitRanges/abc"), Query: buildQueryValues(ns, nil)},
|
||||||
|
Response: Response{StatusCode: 200, Body: limitRange},
|
||||||
|
}
|
||||||
|
response, err := c.Setup().LimitRanges(ns).Update(limitRange)
|
||||||
|
c.Validate(t, response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidLimitRangeUpdate(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
limitRange := &api.LimitRange{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{Method: "PUT", Path: buildResourcePath(ns, "/limitRanges/abc"), Query: buildQueryValues(ns, nil)},
|
||||||
|
Response: Response{StatusCode: 200, Body: limitRange},
|
||||||
|
}
|
||||||
|
_, err := c.Setup().LimitRanges(ns).Update(limitRange)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected an error due to missing ResourceVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRangeDelete(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{Method: "DELETE", Path: buildResourcePath(ns, "/limitRanges/foo"), Query: buildQueryValues(ns, nil)},
|
||||||
|
Response: Response{StatusCode: 200},
|
||||||
|
}
|
||||||
|
err := c.Setup().LimitRanges(ns).Delete("foo")
|
||||||
|
c.Validate(t, nil, err)
|
||||||
|
}
|
@ -47,10 +47,66 @@ func DescriberFor(kind string, c *client.Client) (Describer, bool) {
|
|||||||
return &ServiceDescriber{c}, true
|
return &ServiceDescriber{c}, true
|
||||||
case "Minion", "Node":
|
case "Minion", "Node":
|
||||||
return &MinionDescriber{c}, true
|
return &MinionDescriber{c}, true
|
||||||
|
case "LimitRange":
|
||||||
|
return &LimitRangeDescriber{c}, true
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitRangeDescriber generates information about a limit range
|
||||||
|
type LimitRangeDescriber struct {
|
||||||
|
client.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LimitRangeDescriber) Describe(namespace, name string) (string, error) {
|
||||||
|
lr := d.LimitRanges(namespace)
|
||||||
|
|
||||||
|
limitRange, err := lr.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabbedString(func(out io.Writer) error {
|
||||||
|
fmt.Fprintf(out, "Name:\t%s\n", limitRange.Name)
|
||||||
|
fmt.Fprintf(out, "Kind\tResource\tMin\tMax\n")
|
||||||
|
fmt.Fprintf(out, "----\t--------\t---\t---\n")
|
||||||
|
for i, _ := range limitRange.Spec.Limits {
|
||||||
|
item := limitRange.Spec.Limits[i]
|
||||||
|
kind := item.Kind
|
||||||
|
maxResources := item.Max
|
||||||
|
minResources := item.Min
|
||||||
|
|
||||||
|
set := map[api.ResourceName]bool{}
|
||||||
|
for k, _ := range maxResources {
|
||||||
|
set[k] = true
|
||||||
|
}
|
||||||
|
for k, _ := range minResources {
|
||||||
|
set[k] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, _ := range set {
|
||||||
|
// if no value is set, we output -
|
||||||
|
maxValue := "-"
|
||||||
|
minValue := "-"
|
||||||
|
|
||||||
|
maxQuantity, maxQuantityFound := maxResources[k]
|
||||||
|
if maxQuantityFound {
|
||||||
|
maxValue = maxQuantity.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
minQuantity, minQuantityFound := minResources[k]
|
||||||
|
if minQuantityFound {
|
||||||
|
minValue = minQuantity.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := "%v\t%v\t%v\t%v\n"
|
||||||
|
fmt.Fprintf(out, msg, kind, k, minValue, maxValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// PodDescriber generates information about a pod and the replication controllers that
|
// PodDescriber generates information about a pod and the replication controllers that
|
||||||
// create it.
|
// create it.
|
||||||
type PodDescriber struct {
|
type PodDescriber struct {
|
||||||
|
@ -143,11 +143,12 @@ func (e ShortcutExpander) VersionAndKindForResource(resource string) (defaultVer
|
|||||||
// indeed a shortcut. Otherwise, will return resource unmodified.
|
// indeed a shortcut. Otherwise, will return resource unmodified.
|
||||||
func expandResourceShortcut(resource string) string {
|
func expandResourceShortcut(resource string) string {
|
||||||
shortForms := map[string]string{
|
shortForms := map[string]string{
|
||||||
"po": "pods",
|
"po": "pods",
|
||||||
"rc": "replicationcontrollers",
|
"rc": "replicationcontrollers",
|
||||||
"se": "services",
|
"se": "services",
|
||||||
"mi": "minions",
|
"mi": "minions",
|
||||||
"ev": "events",
|
"ev": "events",
|
||||||
|
"limits": "limitRanges",
|
||||||
}
|
}
|
||||||
if expanded, ok := shortForms[resource]; ok {
|
if expanded, ok := shortForms[resource]; ok {
|
||||||
return expanded
|
return expanded
|
||||||
|
@ -221,6 +221,7 @@ var serviceColumns = []string{"NAME", "LABELS", "SELECTOR", "IP", "PORT"}
|
|||||||
var minionColumns = []string{"NAME", "LABELS", "STATUS"}
|
var minionColumns = []string{"NAME", "LABELS", "STATUS"}
|
||||||
var statusColumns = []string{"STATUS"}
|
var statusColumns = []string{"STATUS"}
|
||||||
var eventColumns = []string{"TIME", "NAME", "KIND", "SUBOBJECT", "REASON", "SOURCE", "MESSAGE"}
|
var eventColumns = []string{"TIME", "NAME", "KIND", "SUBOBJECT", "REASON", "SOURCE", "MESSAGE"}
|
||||||
|
var limitRangeColumns = []string{"NAME"}
|
||||||
|
|
||||||
// addDefaultHandlers adds print handlers for default Kubernetes types.
|
// addDefaultHandlers adds print handlers for default Kubernetes types.
|
||||||
func (h *HumanReadablePrinter) addDefaultHandlers() {
|
func (h *HumanReadablePrinter) addDefaultHandlers() {
|
||||||
@ -235,6 +236,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||||||
h.Handler(statusColumns, printStatus)
|
h.Handler(statusColumns, printStatus)
|
||||||
h.Handler(eventColumns, printEvent)
|
h.Handler(eventColumns, printEvent)
|
||||||
h.Handler(eventColumns, printEventList)
|
h.Handler(eventColumns, printEventList)
|
||||||
|
h.Handler(limitRangeColumns, printLimitRange)
|
||||||
|
h.Handler(limitRangeColumns, printLimitRangeList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||||
@ -409,6 +412,24 @@ func printEventList(list *api.EventList, w io.Writer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printLimitRange(limitRange *api.LimitRange, w io.Writer) error {
|
||||||
|
_, err := fmt.Fprintf(
|
||||||
|
w, "%s\n",
|
||||||
|
limitRange.Name,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the LimitRangeList in a human-friendly format.
|
||||||
|
func printLimitRangeList(list *api.LimitRangeList, w io.Writer) error {
|
||||||
|
for i := range list.Items {
|
||||||
|
if err := printLimitRange(&list.Items[i], w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
|
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
|
||||||
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
||||||
w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
|
w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
|
||||||
|
@ -47,6 +47,7 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/etcd"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/etcd"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/event"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/event"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/limitrange"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||||
@ -109,6 +110,7 @@ type Master struct {
|
|||||||
minionRegistry minion.Registry
|
minionRegistry minion.Registry
|
||||||
bindingRegistry binding.Registry
|
bindingRegistry binding.Registry
|
||||||
eventRegistry generic.Registry
|
eventRegistry generic.Registry
|
||||||
|
limitRangeRegistry generic.Registry
|
||||||
storage map[string]apiserver.RESTStorage
|
storage map[string]apiserver.RESTStorage
|
||||||
client *client.Client
|
client *client.Client
|
||||||
portalNet *net.IPNet
|
portalNet *net.IPNet
|
||||||
@ -248,6 +250,7 @@ func New(c *Config) *Master {
|
|||||||
bindingRegistry: etcd.NewRegistry(c.EtcdHelper, boundPodFactory),
|
bindingRegistry: etcd.NewRegistry(c.EtcdHelper, boundPodFactory),
|
||||||
eventRegistry: event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds())),
|
eventRegistry: event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds())),
|
||||||
minionRegistry: minionRegistry,
|
minionRegistry: minionRegistry,
|
||||||
|
limitRangeRegistry: limitrange.NewEtcdRegistry(c.EtcdHelper),
|
||||||
client: c.Client,
|
client: c.Client,
|
||||||
portalNet: c.PortalNet,
|
portalNet: c.PortalNet,
|
||||||
rootWebService: new(restful.WebService),
|
rootWebService: new(restful.WebService),
|
||||||
@ -361,6 +364,8 @@ func (m *Master) init(c *Config) {
|
|||||||
|
|
||||||
// TODO: should appear only in scheduler API group.
|
// TODO: should appear only in scheduler API group.
|
||||||
"bindings": binding.NewREST(m.bindingRegistry),
|
"bindings": binding.NewREST(m.bindingRegistry),
|
||||||
|
|
||||||
|
"limitRanges": limitrange.NewREST(m.limitRangeRegistry),
|
||||||
}
|
}
|
||||||
|
|
||||||
apiVersions := []string{"v1beta1", "v1beta2"}
|
apiVersions := []string{"v1beta1", "v1beta2"}
|
||||||
|
19
pkg/registry/limitrange/doc.go
Normal file
19
pkg/registry/limitrange/doc.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 limitrange provides Registry interface and it's REST
|
||||||
|
// implementation for storing LimitRange api objects.
|
||||||
|
package limitrange
|
48
pkg/registry/limitrange/registry.go
Normal file
48
pkg/registry/limitrange/registry.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 limitrange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||||
|
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
|
)
|
||||||
|
|
||||||
|
// registry implements custom changes to generic.Etcd.
|
||||||
|
type registry struct {
|
||||||
|
*etcdgeneric.Etcd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEtcdRegistry returns a registry which will store LimitRange in the given helper
|
||||||
|
func NewEtcdRegistry(h tools.EtcdHelper) generic.Registry {
|
||||||
|
return registry{
|
||||||
|
Etcd: &etcdgeneric.Etcd{
|
||||||
|
NewFunc: func() runtime.Object { return &api.LimitRange{} },
|
||||||
|
NewListFunc: func() runtime.Object { return &api.LimitRangeList{} },
|
||||||
|
EndpointName: "limitranges",
|
||||||
|
KeyRootFunc: func(ctx api.Context) string {
|
||||||
|
return etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/limitranges")
|
||||||
|
},
|
||||||
|
KeyFunc: func(ctx api.Context, id string) (string, error) {
|
||||||
|
return etcdgeneric.NamespaceKeyFunc(ctx, "/registry/limitranges", id)
|
||||||
|
},
|
||||||
|
Helper: h,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
121
pkg/registry/limitrange/registry_test.go
Normal file
121
pkg/registry/limitrange/registry_test.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 limitrange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||||
|
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
|
"github.com/coreos/go-etcd/etcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTestLimitRangeEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) {
|
||||||
|
f := tools.NewFakeEtcdClient(t)
|
||||||
|
f.TestIndex = true
|
||||||
|
h := tools.EtcdHelper{f, testapi.Codec(), tools.RuntimeVersionAdapter{testapi.MetadataAccessor()}}
|
||||||
|
return f, NewEtcdRegistry(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimitRangeCreate(t *testing.T) {
|
||||||
|
limitRange := &api.LimitRange{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc",
|
||||||
|
Namespace: "foo",
|
||||||
|
},
|
||||||
|
Spec: api.LimitRangeSpec{
|
||||||
|
Limits: []api.LimitRangeItem{
|
||||||
|
{
|
||||||
|
Kind: "pods",
|
||||||
|
Max: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100"),
|
||||||
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
|
},
|
||||||
|
Min: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("0"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeWithLimitRange := tools.EtcdResponseWithError{
|
||||||
|
R: &etcd.Response{
|
||||||
|
Node: &etcd.Node{
|
||||||
|
Value: runtime.EncodeOrDie(testapi.Codec(), limitRange),
|
||||||
|
ModifiedIndex: 1,
|
||||||
|
CreatedIndex: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
E: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyNode := tools.EtcdResponseWithError{
|
||||||
|
R: &etcd.Response{},
|
||||||
|
E: tools.EtcdErrorNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := api.NewDefaultContext()
|
||||||
|
key := "foo"
|
||||||
|
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/registry/limitranges", key)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table := map[string]struct {
|
||||||
|
existing tools.EtcdResponseWithError
|
||||||
|
expect tools.EtcdResponseWithError
|
||||||
|
toCreate runtime.Object
|
||||||
|
errOK func(error) bool
|
||||||
|
}{
|
||||||
|
"normal": {
|
||||||
|
existing: emptyNode,
|
||||||
|
expect: nodeWithLimitRange,
|
||||||
|
toCreate: limitRange,
|
||||||
|
errOK: func(err error) bool { return err == nil },
|
||||||
|
},
|
||||||
|
"preExisting": {
|
||||||
|
existing: nodeWithLimitRange,
|
||||||
|
expect: nodeWithLimitRange,
|
||||||
|
toCreate: limitRange,
|
||||||
|
errOK: errors.IsAlreadyExists,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, item := range table {
|
||||||
|
fakeClient, registry := NewTestLimitRangeEtcdRegistry(t)
|
||||||
|
fakeClient.Data[path] = item.existing
|
||||||
|
err := registry.Create(ctx, key, item.toCreate)
|
||||||
|
if !item.errOK(err) {
|
||||||
|
t.Errorf("%v: unexpected error: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) {
|
||||||
|
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
159
pkg/registry/limitrange/rest.go
Normal file
159
pkg/registry/limitrange/rest.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 limitrange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// REST provides the RESTStorage access patterns to work with LimitRange objects.
|
||||||
|
type REST struct {
|
||||||
|
registry generic.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewREST returns a new REST. You must use a registry created by
|
||||||
|
// NewEtcdRegistry unless you're testing.
|
||||||
|
func NewREST(registry generic.Registry) *REST {
|
||||||
|
return &REST{
|
||||||
|
registry: registry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a LimitRange object
|
||||||
|
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||||
|
limitRange, ok := obj.(*api.LimitRange)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid object type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !api.ValidNamespace(ctx, &limitRange.ObjectMeta) {
|
||||||
|
return nil, errors.NewConflict("limitRange", limitRange.Namespace, fmt.Errorf("LimitRange.Namespace does not match the provided context"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(limitRange.Name) == 0 {
|
||||||
|
limitRange.Name = string(util.NewUUID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs := validation.ValidateLimitRange(limitRange); len(errs) > 0 {
|
||||||
|
return nil, errors.NewInvalid("limitRange", limitRange.Name, errs)
|
||||||
|
}
|
||||||
|
api.FillObjectMetaSystemFields(ctx, &limitRange.ObjectMeta)
|
||||||
|
|
||||||
|
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||||
|
err := rs.registry.Create(ctx, limitRange.Name, limitRange)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.registry.Get(ctx, limitRange.Name)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates a LimitRange object.
|
||||||
|
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||||
|
limitRange, ok := obj.(*api.LimitRange)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid object type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !api.ValidNamespace(ctx, &limitRange.ObjectMeta) {
|
||||||
|
return nil, errors.NewConflict("limitRange", limitRange.Namespace, fmt.Errorf("LimitRange.Namespace does not match the provided context"))
|
||||||
|
}
|
||||||
|
|
||||||
|
oldObj, err := rs.registry.Get(ctx, limitRange.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
editLimitRange := oldObj.(*api.LimitRange)
|
||||||
|
|
||||||
|
// set the editable fields on the existing object
|
||||||
|
editLimitRange.Labels = limitRange.Labels
|
||||||
|
editLimitRange.ResourceVersion = limitRange.ResourceVersion
|
||||||
|
editLimitRange.Annotations = limitRange.Annotations
|
||||||
|
editLimitRange.Spec = limitRange.Spec
|
||||||
|
|
||||||
|
if errs := validation.ValidateLimitRange(editLimitRange); len(errs) > 0 {
|
||||||
|
return nil, errors.NewInvalid("limitRange", editLimitRange.Name, errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||||
|
err := rs.registry.Update(ctx, editLimitRange.Name, editLimitRange)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.registry.Get(ctx, editLimitRange.Name)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the LimitRange with the specified name
|
||||||
|
func (rs *REST) Delete(ctx api.Context, name string) (<-chan apiserver.RESTResult, error) {
|
||||||
|
obj, err := rs.registry.Get(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, ok := obj.(*api.LimitRange)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid object type")
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||||
|
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, name)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets a LimitRange with the specified name
|
||||||
|
func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||||
|
obj, err := rs.registry.Get(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
limitRange, ok := obj.(*api.LimitRange)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid object type")
|
||||||
|
}
|
||||||
|
return limitRange, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) {
|
||||||
|
return labels.Set{}, labels.Set{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) {
|
||||||
|
return rs.registry.List(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return rs.registry.Watch(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new api.LimitRange
|
||||||
|
func (*REST) New() runtime.Object {
|
||||||
|
return &api.LimitRange{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*REST) NewList() runtime.Object {
|
||||||
|
return &api.LimitRangeList{}
|
||||||
|
}
|
17
pkg/registry/limitrange/rest_test.go
Normal file
17
pkg/registry/limitrange/rest_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 limitrange
|
Loading…
Reference in New Issue
Block a user