Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ RUN go mod download
# Copy the go source
COPY cmd/ cmd/
COPY internal/ internal/
COPY pkg/ pkg/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
Expand Down
36 changes: 26 additions & 10 deletions cmd/controller/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
cliflag "k8s.io/component-base/cli/flag"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/healthz"
Expand All @@ -29,8 +31,12 @@ import (
// +kubebuilder:scaffold:imports
"go.datum.net/datum/internal/config"
resourcemanagercontroller "go.datum.net/datum/internal/controller/resourcemanager"
"go.datum.net/datum/pkg/features"
iamv1alpha1 "go.miloapis.com/milo/pkg/apis/iam/v1alpha1"
resourcemanagerv1alpha1 "go.miloapis.com/milo/pkg/apis/resourcemanager/v1alpha1"

// Register Datum feature gates via init().
_ "go.datum.net/datum/pkg/features"
)

var (
Expand Down Expand Up @@ -134,6 +140,12 @@ func NewControllerManagerCommand() *cobra.Command {
cmd.Flags().AddGoFlagSet(flag.CommandLine)
opts.BindFlags(flag.CommandLine)

namedFlagSets := cliflag.NamedFlagSets{}
utilfeature.DefaultMutableFeatureGate.AddFlag(namedFlagSets.FlagSet("feature gates"))
for _, fs := range namedFlagSets.FlagSets {
cmd.Flags().AddFlagSet(fs)
}

return cmd
}

Expand Down Expand Up @@ -286,16 +298,6 @@ func runControllerManager(
return err
}

if err = (&resourcemanagercontroller.PersonalOrganizationController{
Client: mgr.GetClient(),
Config: serverConfig.PersonalOrganizationController,
Scheme: mgr.GetScheme(),
RestConfig: mgr.GetConfig(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PersonalOrganization")
return err
}

// +kubebuilder:scaffold:builder

if metricsCertWatcher != nil {
Expand Down Expand Up @@ -323,6 +325,20 @@ func runControllerManager(
return err
}

if !utilfeature.DefaultFeatureGate.Enabled(features.UnifiedOrganizations) {
if err = (&resourcemanagercontroller.PersonalOrganizationController{
Client: mgr.GetClient(),
Config: serverConfig.PersonalOrganizationController,
Scheme: mgr.GetScheme(),
RestConfig: mgr.GetConfig(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PersonalOrganization")
return err
}
} else {
setupLog.Info("PersonalOrganization controller disabled by UnifiedOrganizations feature gate")
}

setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
Expand Down
21 changes: 21 additions & 0 deletions config/overlays/unified-organizations/README.md

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should default to the existing behavior to prevent breaking changes on release. This lets us only modify the staging environment to enable the new functionality instead of having to coordinate between all environments.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Unified organizations overlay

Apply this kustomize component when `UnifiedOrganizations=true` on milo and datum
controller-managers. It replaces legacy personal/standard project quota grant
policies with a single 10-project policy for all organizations and removes the
personal organization display-name validation policy.

The default datum service configuration keeps legacy behavior so releases do not
require coordinated cutover across environments. Only environments that opt in
(staging first) should apply this overlay together with the feature gate.

## Usage

Include as a component in your environment kustomization:

```yaml
components:
- ../path/to/datum/config/overlays/unified-organizations
```

Ensure milo and datum controller-managers run with `UnifiedOrganizations=true`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: quota.miloapis.com/v1alpha1
kind: GrantCreationPolicy
metadata:
name: organization-project-quota-policy
labels:
app.kubernetes.io/name: datum
app.kubernetes.io/component: quota-system
spec:
trigger:
resource:
apiVersion: resourcemanager.miloapis.com/v1alpha1
kind: Organization
target:
resourceGrantTemplate:
metadata:
name: "default-project-quota"
namespace: "organization-{{ trigger.metadata.name }}"
labels:
quota.miloapis.com/auto-created: "true"
quota.miloapis.com/policy: "organization-project-quota-policy"
annotations:
kubernetes.io/description: "Project quota allocation for organization"
spec:
consumerRef:
apiGroup: resourcemanager.miloapis.com
kind: Organization
name: "{{ trigger.metadata.name }}"
allowances:
- resourceType: resourcemanager.miloapis.com/projects
buckets:
- amount: 10
23 changes: 23 additions & 0 deletions config/overlays/unified-organizations/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
- grant-policies/organization-project-quota-policy.yaml

patches:
- path: remove-personal-grant-policy.yaml
target:
kind: GrantCreationPolicy
name: personal-organization-project-quota-policy
- path: remove-standard-grant-policy.yaml
target:
kind: GrantCreationPolicy
name: standard-organization-project-quota-policy
- path: remove-personal-org-name-vap.yaml
target:
kind: ValidatingAdmissionPolicy
name: disallow-personal-org-name-change
- path: remove-personal-org-name-vap-binding.yaml
target:
kind: ValidatingAdmissionPolicyBinding
name: disallow-personal-org-name-change
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$patch: delete
apiVersion: quota.miloapis.com/v1alpha1
kind: GrantCreationPolicy
metadata:
name: personal-organization-project-quota-policy
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$patch: delete
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: disallow-personal-org-name-change
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$patch: delete
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: disallow-personal-org-name-change
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$patch: delete
apiVersion: quota.miloapis.com/v1alpha1
kind: GrantCreationPolicy
metadata:
name: standard-organization-project-quota-policy
11 changes: 11 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@ rules:
- organizations
verbs:
- create
- apiGroups:
- resourcemanager.datumapis.com
resources:
- projects
verbs:
- create
- get
- list
- patch
- update
- watch
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ spec:
name: "default-dns-quota-{{ trigger.metadata.name }}"
namespace: milo-system
annotations:
kubernetes.io/description: "DNS quota allocation for Personal org project"
kubernetes.io/description: "DNS quota allocation for organization project"
spec:
consumerRef:
apiGroup: resourcemanager.miloapis.com
Expand Down
13 changes: 9 additions & 4 deletions config/services/resourcemanager.miloapis.com/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@ customize it for Datum Cloud.

## Quota Limits

The default configuration ships legacy personal/standard quota grant policies:

- **Personal Organizations**: 2 project maximum
- **Standard Organizations**: 10 projects maximum

When enabling unified organizations, apply `config/overlays/unified-organizations`
with `UnifiedOrganizations=true` on milo and datum controller-managers for a
single 10-project quota policy on all organizations.

## Deployment

```bash
# Deploy entire service
# Deploy entire service (legacy quota policies by default)
kubectl apply -k config/services/resourcemanager.miloapis.com

# Deploy specific components
kubectl apply -k config/services/resourcemanager.miloapis.com/quota
kubectl apply -k config/services/resourcemanager.miloapis.com/validation
# Unified environments: also apply unified overlay and enable feature gate
kubectl apply -k config/overlays/unified-organizations
```
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ require (
go.miloapis.com/milo v0.25.1
k8s.io/api v0.32.3
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.32.3
k8s.io/client-go v0.32.3
k8s.io/component-base v0.32.3
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/controller-runtime v0.20.4
)
Expand Down Expand Up @@ -95,8 +97,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.32.3 // indirect
k8s.io/apiserver v0.32.3 // indirect
k8s.io/component-base v0.32.3 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
Expand Down
Loading