-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Epic: #1
Phase: 1 - Foundation & Code Changes
Dependencies: None (START HERE)
Estimate: 8 hours
Description
Add comprehensive single-namespace mode support to the operator to enable deployment in MPP environments where cluster-wide permissions are not available.
Critical Issues Addressed
This issue resolves 4 of the 8 critical showstoppers:
- ✅ Operator watching all namespaces without filter ([Phase 1] Disable project creation endpoint in backend for single-namespace mode #3)
- ✅ Namespace watcher cannot be disabled ([Phase 1] Add unit tests for single-namespace mode #4)
- ✅ Missing StorageClass parameter ([Phase 2] Convert ClusterRoles to namespace-scoped Roles #5)
- ✅ Missing pod security contexts ([Phase 2] Update operator to reference namespace Roles instead of ClusterRoles #6)
Implementation Tasks
1. Add Environment Variable Support
File: components/operator/main.go
Add global variables:
var (
singleNamespaceMode bool
storageClass string
)Initialize in main():
singleNamespaceMode = os.Getenv("SINGLE_NAMESPACE_MODE") == "true"
storageClass = os.Getenv("STORAGE_CLASS")
if storageClass == "" {
storageClass = "gp3-csi"
}
if singleNamespaceMode {
log.Printf("Running in SINGLE_NAMESPACE_MODE, watching namespace: %s", namespace)
}2. Disable Namespace Watcher
File: components/operator/main.go (line ~83)
// Start watchers
go watchAgenticSessions()
go watchProjectSettings()
// Only watch namespaces in multi-namespace mode
if !singleNamespaceMode {
go watchNamespaces()
} else {
// Bootstrap single namespace resources
if err := ensureProjectWorkspacePVC(namespace); err != nil {
log.Fatalf("Failed to ensure workspace PVC: %v", err)
}
if err := ensureContentService(namespace); err != nil {
log.Fatalf("Failed to ensure content service: %v", err)
}
}3. Add Namespace Filtering to Watch Functions
File: components/operator/main.go (watchAgenticSessions, line ~140)
func watchAgenticSessions() {
gvr := getAgenticSessionResource()
for {
var watcher watch.Interface
var err error
if singleNamespaceMode {
watcher, err = dynamicClient.Resource(gvr).Namespace(namespace).Watch(context.TODO(), v1.ListOptions{})
} else {
watcher, err = dynamicClient.Resource(gvr).Watch(context.TODO(), v1.ListOptions{})
}
if err != nil {
log.Printf("Failed to create AgenticSession watcher: %v", err)
time.Sleep(5 * time.Second)
continue
}
// ... rest of logic, but skip managed namespace check in single-namespace mode
for event := range watcher.ResultChan() {
// ... existing event handling ...
// Only check namespace labels when watching all namespaces
if !singleNamespaceMode {
ns := obj.GetNamespace()
nsObj, err := k8sClient.CoreV1().Namespaces().Get(context.TODO(), ns, v1.GetOptions{})
if err != nil {
log.Printf("Failed to get namespace %s: %v", ns, err)
continue
}
if nsObj.Labels["ambient-code.io/managed"] != "true" {
continue
}
}
// ... handle event ...
}
}
}Apply same pattern to watchProjectSettings() (line ~769)
4. Add StorageClass Parameter to PVC Creation
File: components/operator/main.go (ensureProjectWorkspacePVC, line ~533)
pvc := &corev1.PersistentVolumeClaim{
ObjectMeta: v1.ObjectMeta{
Name: "ambient-workspace",
Namespace: namespace,
Labels: map[string]string{"app": "ambient-workspace"},
},
Spec: corev1.PersistentVolumeClaimSpec{
StorageClassName: &storageClass, // ← ADD THIS LINE
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse("5Gi"),
},
},
},
}5. Add Pod Security Context to Job Template
File: components/operator/main.go (handleAgenticSessionEvent, line ~330)
job := &batchv1.Job{
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
// ← ADD POD-LEVEL SECURITY CONTEXT
SecurityContext: &corev1.PodSecurityContext{
RunAsNonRoot: boolPtr(true),
FSGroup: int64Ptr(1000),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
},
RestartPolicy: corev1.RestartPolicyNever,
// ... rest of spec ...
}
}
}
}6. Add Pod Security Context to Content Service
File: components/operator/main.go (ensureContentService, line ~568)
Add same pod security context to content service deployment.
Testing Requirements
- Operator starts successfully with
SINGLE_NAMESPACE_MODE=true - Operator does NOT attempt to watch namespaces cluster-wide
- PVC created with
gp3-csistorage class - Job pods include pod-level security context
- No RBAC permission errors in operator logs
Acceptance Criteria
- Environment variables added and documented
- Namespace watcher disabled in single-namespace mode
- All watch functions namespace-scoped when enabled
- StorageClass parameter added to PVC creation
- Pod security contexts added to Job and content service
- Operator starts without cluster-wide permissions
- Code reviewed and tested
Files Changed
components/operator/main.go
Branch
feature/mpp-single-namespace-mode