Skip to content

Commit

Permalink
Support resource quota at namespace level
Browse files Browse the repository at this point in the history
Signed-off-by: Tamal Saha <[email protected]>
  • Loading branch information
tamalsaha committed Aug 28, 2024
1 parent c8366da commit 7580b7e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 41 deletions.
48 changes: 37 additions & 11 deletions pkg/controllers/projectquota/projectquota_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ func (r *ProjectQuotaReconciler) Reconcile(ctx context.Context, req ctrl.Request

var pj v1alpha1.ProjectQuota
if err := r.Get(ctx, req.NamespacedName, &pj); err != nil {
log.Error(err, "unable to fetch ProjectQuota")
return ctrl.Result{}, client.IgnoreNotFound(err)
}

Expand Down Expand Up @@ -164,10 +163,7 @@ type QuotaResult struct {
}

func (r *ProjectQuotaReconciler) CalculateStatus(pj *v1alpha1.ProjectQuota) error {
var nsList core.NamespaceList
err := r.List(context.TODO(), &nsList, client.MatchingLabels{
clustermeta.LabelKeyRancherFieldProjectId: pj.Name,
})
nsList, err := r.getNamespaceList(pj.Name)
if err != nil {
return err
}
Expand Down Expand Up @@ -266,6 +262,29 @@ func (r *ProjectQuotaReconciler) CalculateStatus(pj *v1alpha1.ProjectQuota) erro
return nil
}

func (r *ProjectQuotaReconciler) getNamespaceList(name string) (*core.NamespaceList, error) {
var nsList core.NamespaceList
if clustermeta.IsRancherManaged(r.RESTMapper()) {
err := r.List(context.TODO(), &nsList, client.MatchingLabels{
clustermeta.LabelKeyRancherFieldProjectId: name,
})
if err != nil {
return nil, err
}
if len(nsList.Items) > 0 {
return &nsList, nil
}
}

err := r.List(context.TODO(), &nsList, client.MatchingLabels{
core.LabelMetadataName: name,
})
if err != nil {
return nil, err
}
return &nsList, nil
}

func (r *ProjectQuotaReconciler) UsedQuota(ns string, typeInfo APIType) (core.ResourceList, *QuotaResult, error) {
gk := schema.GroupKind{
Group: typeInfo.Group,
Expand Down Expand Up @@ -394,12 +413,19 @@ func ProjectQuotaForObjects(kc client.Client) func(_ context.Context, _ client.O
return nil
}

projectId, found := ns.Labels[clustermeta.LabelKeyRancherFieldProjectId]
if !found {
return nil
}
return []reconcile.Request{
{NamespacedName: types.NamespacedName{Name: projectId}},
var req []reconcile.Request

if clustermeta.IsRancherManaged(kc.RESTMapper()) {
projectId, found := ns.Labels[clustermeta.LabelKeyRancherFieldProjectId]
if found {
req = append(req, reconcile.Request{
NamespacedName: types.NamespacedName{Name: projectId},
})
}
}
req = append(req, reconcile.Request{
NamespacedName: types.NamespacedName{Name: ns.Name},
})
return req
}
}
31 changes: 19 additions & 12 deletions pkg/registry/meta/resourcecalculator/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"strings"

core "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -101,20 +100,28 @@ func mergeRequestsLimits(requests, limits core.ResourceList) core.ResourceList {
return rl
}

func getProjectQuota(kc client.Client, ns string) (*v1alpha1.ProjectQuota, error) {
projectId, _, err := clustermeta.GetProjectId(kc, ns)
if err != nil {
return nil, err
func getProjectQuotas(kc client.Client, ns string) ([]*v1alpha1.ProjectQuota, error) {
var names []string
if clustermeta.IsRancherManaged(kc.RESTMapper()) {
projectId, _, err := clustermeta.GetProjectId(kc, ns)
if err != nil {
return nil, err
}
names = append(names, projectId)
}
var pj v1alpha1.ProjectQuota
err = kc.Get(context.TODO(), client.ObjectKey{Name: projectId}, &pj)
if err != nil {
if apierrors.IsNotFound(err) {
return nil, nil
names = append(names, ns)

var result []*v1alpha1.ProjectQuota
for _, name := range names {
var pj v1alpha1.ProjectQuota
err := kc.Get(context.TODO(), client.ObjectKey{Name: name}, &pj)
if client.IgnoreNotFound(err) != nil {
return nil, err
} else if err == nil {
result = append(result, &pj)
}
return nil, err
}
return &pj, nil
return result, nil
}

func getGVK(obj map[string]interface{}) schema.GroupVersionKind {
Expand Down
50 changes: 32 additions & 18 deletions pkg/registry/meta/resourcecalculator/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,26 +108,40 @@ func (r *Storage) Create(ctx context.Context, obj runtime.Object, createValidati
}
rid := kmapi.NewResourceID(mapping)

pq, err := getProjectQuota(r.kc, u.GetNamespace())
if err != nil {
return nil, err
}
// Wrap referenced db resource with the OpsRequest object
if rid.Group == "ops.kubedb.com" {
if err = utils.ExpandReferencedAppInOpsObject(r.kc, &u); err != nil {
return nil, err
}
} else if in.Request.Edit && pq != nil {
if err := deductOldDbObjectResourceUsageFromProjectQuota(r.kc, u, pq); err != nil {
return nil, err
}
}

resp, err := ToGenericResource(&u, rid, pq)
resp, err := ToGenericResource(&u, rid)
if err != nil {
return nil, apierrors.NewInternalError(err)
}

quotas, err := getProjectQuotas(r.kc, u.GetNamespace())
if err != nil {
return nil, err
}
// Wrap referenced db resource with the OpsRequest object
for i := range quotas {
pq := quotas[i]
if rid.Group != "ops.kubedb.com" && in.Request.Edit {
if err := deductOldDbObjectResourceUsageFromProjectQuota(r.kc, u, pq); err != nil {
return nil, err
}
}

rv, err := quota(u.UnstructuredContent(), pq)
if err != nil {
return nil, err
}
resp.Quota = *rv
if rv.Decision == rsapi.DecisionDeny {
break
}
}

in.Response = resp
return in, nil
}
Expand All @@ -136,7 +150,7 @@ func (r *Storage) ConvertToTable(ctx context.Context, object runtime.Object, tab
return r.convertor.ConvertToTable(ctx, object, tableOptions)
}

func ToGenericResource(item *unstructured.Unstructured, apiType *kmapi.ResourceID, pq *v1alpha1.ProjectQuota) (*rsapi.ResourceCalculatorResponse, error) {
func ToGenericResource(item *unstructured.Unstructured, apiType *kmapi.ResourceID) (*rsapi.ResourceCalculatorResponse, error) {
content := item.UnstructuredContent()

var genres rsapi.ResourceCalculatorResponse
Expand Down Expand Up @@ -210,13 +224,13 @@ func ToGenericResource(item *unstructured.Unstructured, apiType *kmapi.ResourceI
}
genres.RoleResourceLimits = rv
}
{
rv, err := quota(content, pq)
if err != nil {
return nil, err
}
genres.Quota = *rv
}
//{
// rv, err := quota(content, pq)
// if err != nil {
// return nil, err
// }
// genres.Quota = *rv
//}
}
return &genres, nil
}
Expand Down

0 comments on commit 7580b7e

Please sign in to comment.