Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admission Control: Resource Quota #3796

Merged
merged 5 commits into from
Jan 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/kube-apiserver/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ import (
_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/deny"
_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger"
_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcedefaults"
_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota"
)
9 changes: 7 additions & 2 deletions cmd/kube-controller-manager/controller-manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resourcequota"
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
Expand All @@ -55,8 +56,9 @@ var (
machineList util.StringList
// TODO: Discover these by pinging the host machines, and rip out these flags.
// TODO: in the meantime, use resource.QuantityFlag() instead of these
nodeMilliCPU = flag.Int64("node_milli_cpu", 1000, "The amount of MilliCPU provisioned on each node")
nodeMemory = resource.QuantityFlag("node_memory", "3Gi", "The amount of memory (in bytes) provisioned on each node")
nodeMilliCPU = flag.Int64("node_milli_cpu", 1000, "The amount of MilliCPU provisioned on each node")
nodeMemory = resource.QuantityFlag("node_memory", "3Gi", "The amount of memory (in bytes) provisioned on each node")
resourceQuotaSyncPeriod = flag.Duration("resource_quota_sync_period", 10*time.Second, "The period for syncing quota usage status in the system")
)

func init() {
Expand Down Expand Up @@ -112,5 +114,8 @@ func main() {
nodeController := nodeControllerPkg.NewNodeController(cloud, *minionRegexp, machineList, nodeResources, kubeClient)
nodeController.Run(*nodeSyncPeriod)

resourceQuotaManager := resourcequota.NewResourceQuotaManager(kubeClient)
resourceQuotaManager.Run(*resourceQuotaSyncPeriod)

select {}
}
15 changes: 15 additions & 0 deletions examples/resourcequota/resource-quota.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "quota",
"kind": "ResourceQuota",
"apiVersion": "v1beta1",
"spec": {
"hard": {
"memory": "1073741824",
"cpu": "20",
"pods": "10",
"services": "5",
"replicationcontrollers":"20",
"resourcequotas":"1",
},
}
}
8 changes: 7 additions & 1 deletion pkg/api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ var Semantic = conversion.EqualitiesOrDie(
},
)

var standardResources = util.NewStringSet(string(ResourceMemory), string(ResourceCPU))
var standardResources = util.NewStringSet(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vishh These new resources are going to be official kubernetes resources, and are valid in a ResourceList in the context of a ResourceQuota, but they aren't valid in the context of a Pod's or Container's limit. Does that matter? I can't tell your intent because ValidateResourceName isn't used yet AFAICS.

string(ResourceMemory),
string(ResourceCPU),
string(ResourcePods),
string(ResourceQuotas),
string(ResourceServices),
string(ResourceReplicationControllers))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about ResouceResourceQuotas?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's there already.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it's not named as in your comment. Will update.


func IsStandardResourceName(str string) bool {
return standardResources.Has(str)
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ func init() {
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceQuota{},
&ResourceQuotaList{},
&ResourceQuotaUsage{},
)
// Legacy names are supported
Scheme.AddKnownTypeWithName("", "Minion", &Node{})
Expand Down Expand Up @@ -81,3 +84,6 @@ func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
func (*LimitRange) IsAnAPIObject() {}
func (*LimitRangeList) IsAnAPIObject() {}
func (*ResourceQuota) IsAnAPIObject() {}
func (*ResourceQuotaList) IsAnAPIObject() {}
func (*ResourceQuotaUsage) IsAnAPIObject() {}
57 changes: 57 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1176,3 +1176,60 @@ type LimitRangeList struct {
// Items is a list of LimitRange objects
Items []LimitRange `json:"items"`
}

// The following identify resource constants for Kubernetes object types
const (
// Pods, number
ResourcePods ResourceName = "pods"
// Services, number
ResourceServices ResourceName = "services"
// ReplicationControllers, number
ResourceReplicationControllers ResourceName = "replicationcontrollers"
// ResourceQuotas, number
ResourceQuotas ResourceName = "resourcequotas"
)

// ResourceQuotaSpec defines the desired hard limits to enforce for Quota
type ResourceQuotaSpec struct {
// Hard is the set of desired hard limits for each named resource
Hard ResourceList `json:"hard,omitempty"`
}

// ResourceQuotaStatus defines the enforced hard limits and observed use
type ResourceQuotaStatus struct {
// Hard is the set of enforced hard limits for each named resource
Hard ResourceList `json:"hard,omitempty"`
// Used is the current observed total usage of the resource in the namespace
Used ResourceList `json:"used,omitempty"`
}

// ResourceQuota sets aggregate quota restrictions enforced per namespace
type ResourceQuota struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`

// Spec defines the desired quota
Spec ResourceQuotaSpec `json:"spec,omitempty"`

// Status defines the actual enforced quota and its current usage
Status ResourceQuotaStatus `json:"status,omitempty"`
}

// ResourceQuotaUsage captures system observed quota status per namespace
// It is used to enforce atomic updates of a backing ResourceQuota.Status field in storage
type ResourceQuotaUsage struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`

// Status defines the actual enforced quota and its current usage
Status ResourceQuotaStatus `json:"status,omitempty"`
}

// ResourceQuotaList is a list of ResourceQuota items
type ResourceQuotaList struct {
TypeMeta `json:",inline"`
ListMeta `json:"metadata,omitempty"`

// Items is a list of ResourceQuota objects
Items []ResourceQuota `json:"items"`
}
88 changes: 88 additions & 0 deletions pkg/api/v1beta1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,94 @@ func init() {
}
return nil
},
func(in *newer.ResourceQuota, out *ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuota, out *newer.ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *newer.ResourceQuotaUsage, out *ResourceQuotaUsage, 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.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaUsage, out *newer.ResourceQuotaUsage, 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.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *newer.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error {
*out = ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaSpec, out *newer.ResourceQuotaSpec, s conversion.Scope) error {
*out = newer.ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *newer.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error {
*out = ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaStatus, out *newer.ResourceQuotaStatus, s conversion.Scope) error {
*out = newer.ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
// Object ID <-> Name
// TODO: amend the conversion package to allow overriding specific fields.
func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error {
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/v1beta1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ func init() {
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceQuota{},
&ResourceQuotaList{},
&ResourceQuotaUsage{},
)
// Future names are supported
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
Expand Down Expand Up @@ -82,3 +85,6 @@ func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
func (*LimitRange) IsAnAPIObject() {}
func (*LimitRangeList) IsAnAPIObject() {}
func (*ResourceQuota) IsAnAPIObject() {}
func (*ResourceQuotaList) IsAnAPIObject() {}
func (*ResourceQuotaUsage) IsAnAPIObject() {}
54 changes: 54 additions & 0 deletions pkg/api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -934,3 +934,57 @@ type LimitRangeList struct {
// Items is a list of LimitRange objects
Items []LimitRange `json:"items"`
}

// The following identify resource constants for Kubernetes object types
const (
// Pods, number
ResourcePods ResourceName = "pods"
// Services, number
ResourceServices ResourceName = "services"
// ReplicationControllers, number
ResourceReplicationControllers ResourceName = "replicationcontrollers"
// ResourceQuotas, number
ResourceQuotas ResourceName = "resourcequotas"
)

// ResourceQuotaSpec defines the desired hard limits to enforce for Quota
type ResourceQuotaSpec struct {
// Hard is the set of desired hard limits for each named resource
Hard ResourceList `json:"hard,omitempty"`
}

// ResourceQuotaStatus defines the enforced hard limits and observed use
type ResourceQuotaStatus struct {
// Hard is the set of enforced hard limits for each named resource
Hard ResourceList `json:"hard,omitempty"`
// Used is the current observed total usage of the resource in the namespace
Used ResourceList `json:"used,omitempty"`
}

// ResourceQuota sets aggregate quota restrictions enforced per namespace
type ResourceQuota struct {
TypeMeta `json:",inline"`

// Spec defines the desired quota
Spec ResourceQuotaSpec `json:"spec,omitempty"`

// Status defines the actual enforced quota and its current usage
Status ResourceQuotaStatus `json:"status,omitempty"`
}

// ResourceQuotaUsage captures system observed quota status per namespace
// It is used to enforce atomic updates of a backing ResourceQuota.Status field in storage
type ResourceQuotaUsage struct {
TypeMeta `json:",inline"`

// Status defines the actual enforced quota and its current usage
Status ResourceQuotaStatus `json:"status,omitempty"`
}

// ResourceQuotaList is a list of ResourceQuota items
type ResourceQuotaList struct {
TypeMeta `json:",inline"`

// Items is a list of ResourceQuota objects
Items []ResourceQuota `json:"items"`
}