add quota left to namespace quota
This commit is contained in:
@@ -180,6 +180,7 @@ func addWebService(c *restful.Container) error {
|
|||||||
|
|
||||||
webservice.Route(webservice.GET("/quotas").
|
webservice.Route(webservice.GET("/quotas").
|
||||||
To(quotas.GetClusterQuotas).
|
To(quotas.GetClusterQuotas).
|
||||||
|
Deprecate().
|
||||||
Doc("get whole cluster's resource usage").
|
Doc("get whole cluster's resource usage").
|
||||||
Writes(models.ResourceQuota{}).
|
Writes(models.ResourceQuota{}).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
|||||||
@@ -37,18 +37,33 @@ const (
|
|||||||
servicesKey = "count/services"
|
servicesKey = "count/services"
|
||||||
statefulsetsKey = "count/statefulsets.apps"
|
statefulsetsKey = "count/statefulsets.apps"
|
||||||
persistentvolumeclaimsKey = "persistentvolumeclaims"
|
persistentvolumeclaimsKey = "persistentvolumeclaims"
|
||||||
storageClassesKey = "count/storageClass"
|
|
||||||
namespaceKey = "count/namespace"
|
|
||||||
jobsKey = "count/jobs.batch"
|
jobsKey = "count/jobs.batch"
|
||||||
cronJobsKey = "count/cronjobs.batch"
|
cronJobsKey = "count/cronjobs.batch"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NamespacedResourceQuota struct {
|
||||||
|
Namespace string `json:"namespace,omitempty"`
|
||||||
|
|
||||||
|
Data struct {
|
||||||
|
v1.ResourceQuotaStatus
|
||||||
|
|
||||||
|
// quota left status, do the math on the side, cause it's
|
||||||
|
// a lot easier with go-client library
|
||||||
|
Left v1.ResourceList `json:"left,omitempty"`
|
||||||
|
} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
resourceMap = map[string]string{daemonsetsKey: resources.DaemonSets, deploymentsKey: resources.Deployments,
|
resourceMap = map[string]string{
|
||||||
ingressKey: resources.Ingresses, servicesKey: resources.Services,
|
daemonsetsKey: resources.DaemonSets,
|
||||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
deploymentsKey: resources.Deployments,
|
||||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses,
|
ingressKey: resources.Ingresses,
|
||||||
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
servicesKey: resources.Services,
|
||||||
|
statefulsetsKey: resources.StatefulSets,
|
||||||
|
persistentvolumeclaimsKey: resources.PersistentVolumeClaims,
|
||||||
|
podsKey: resources.Pods,
|
||||||
|
jobsKey: resources.Jobs,
|
||||||
|
cronJobsKey: resources.CronJobs}
|
||||||
)
|
)
|
||||||
|
|
||||||
func getUsage(namespace, resource string) (int, error) {
|
func getUsage(namespace, resource string) (int, error) {
|
||||||
@@ -61,12 +76,14 @@ func getUsage(namespace, resource string) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.TotalCount, nil
|
return result.TotalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no one use this api anymore, marked as deprecated
|
||||||
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
||||||
|
|
||||||
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||||
@@ -85,7 +102,7 @@ func GetClusterQuotas() (*models.ResourceQuota, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNamespaceQuotas(namespace string) (*models.ResourceQuota, error) {
|
func GetNamespaceQuotas(namespace string) (*NamespacedResourceQuota, error) {
|
||||||
quota, err := getNamespaceResourceQuota(namespace)
|
quota, err := getNamespaceResourceQuota(namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
@@ -95,23 +112,43 @@ func GetNamespaceQuotas(namespace string) (*models.ResourceQuota, error) {
|
|||||||
quota = &v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
quota = &v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range resourceMap {
|
var resourceQuotaLeft = v1.ResourceList{}
|
||||||
if _, exist := quota.Used[v1.ResourceName(k)]; !exist {
|
|
||||||
if k == namespaceKey || k == storageClassesKey {
|
for key, hardLimit := range quota.Hard {
|
||||||
continue
|
if used, ok := quota.Used[key]; ok {
|
||||||
|
left := hardLimit.DeepCopy()
|
||||||
|
left.Sub(used)
|
||||||
|
if hardLimit.Cmp(used) < 0 {
|
||||||
|
left = resource.MustParse("0")
|
||||||
}
|
}
|
||||||
|
|
||||||
used, err := getUsage(namespace, v)
|
resourceQuotaLeft[key] = left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add extra quota usage, cause user may not specify them
|
||||||
|
for key, val := range resourceMap {
|
||||||
|
// only add them when they don't exist in quotastatus
|
||||||
|
if _, ok := quota.Used[v1.ResourceName(key)]; !ok {
|
||||||
|
used, err := getUsage(namespace, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var quantity resource.Quantity
|
|
||||||
quantity.Set(int64(used))
|
quota.Used[v1.ResourceName(key)] = *(resource.NewQuantity(int64(used), resource.DecimalSI))
|
||||||
quota.Used[v1.ResourceName(k)] = quantity
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.ResourceQuota{Namespace: namespace, Data: *quota}, nil
|
var result = NamespacedResourceQuota{
|
||||||
|
Namespace: namespace,
|
||||||
|
}
|
||||||
|
result.Data.Hard = quota.Hard
|
||||||
|
result.Data.Used = quota.Used
|
||||||
|
result.Data.Left = resourceQuotaLeft
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
||||||
@@ -127,14 +164,16 @@ func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
|||||||
tmpResourceList[res] = usage
|
tmpResourceList[res] = usage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
||||||
resourceQuotaLister := informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
resourceQuotaLister := informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||||
quotaList, err := resourceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
quotaList, err := resourceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
||||||
if err != nil || len(quotaList) == 0 {
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else if len(quotaList) == 0 {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
quotaStatus := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
quotaStatus := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||||
|
|||||||
Reference in New Issue
Block a user