Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

Commit 779a2d3

Browse files
committed
Restructure by feature
HNC has always been divided into three main packages (all inside internal/): reconcilers, validators and mutators. This meant that any one feature (like subnamespace anchors) were split across multiple packages, with their internals exposed to other packages. It also ensured that all tests ran serially. This change refactors those three packages into five major ones (anchor, namespace, hierarchyconfig, hncconfig, and objects), as well as a few minor ones to cover code that's now shared across them (such as integtest). Tested: all integ and smoke tests pass.
1 parent e297652 commit 779a2d3

38 files changed

+1732
-1505
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ all: test docker-build
8484
###################### LOCAL ARTIFACTS #########################
8585

8686
# Run tests
87-
test: build
87+
test: build test-only
88+
89+
test-only:
8890
@echo
8991
@echo "If tests fail due to no matches for kind \"CustomResourceDefinition\" in version \"apiextensions.k8s.io/v1\","
9092
@echo "please remove the old kubebuilder and reinstall it - https://book.kubebuilder.io/quick-start.html#installation"

cmd/manager/main.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@ import (
4141
v1a2 "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
4242
"sigs.k8s.io/hierarchical-namespaces/internal/config"
4343
"sigs.k8s.io/hierarchical-namespaces/internal/forest"
44-
"sigs.k8s.io/hierarchical-namespaces/internal/mutators"
45-
"sigs.k8s.io/hierarchical-namespaces/internal/reconcilers"
44+
"sigs.k8s.io/hierarchical-namespaces/internal/setup"
4645
"sigs.k8s.io/hierarchical-namespaces/internal/stats"
47-
"sigs.k8s.io/hierarchical-namespaces/internal/validators"
4846
)
4947

5048
var (
@@ -183,7 +181,7 @@ func main() {
183181

184182
// Make sure certs are generated and valid if webhooks are enabled and internal certs are used.
185183
setupLog.Info("Starting certificate generation")
186-
certsCreated, err := validators.CreateCertsIfNeeded(mgr, novalidation, internalCert, restartOnSecretRefresh)
184+
certsCreated, err := setup.CreateCertsIfNeeded(mgr, novalidation, internalCert, restartOnSecretRefresh)
187185
if err != nil {
188186
setupLog.Error(err, "unable to set up cert rotation")
189187
os.Exit(1)
@@ -212,19 +210,15 @@ func startControllers(mgr ctrl.Manager, certsCreated chan struct{}) {
212210
// other components.
213211
f := forest.NewForest()
214212

215-
// Create all validating admission controllers.
213+
// Create all validating and mutating admission controllers.
216214
if !novalidation {
217215
setupLog.Info("Registering validating webhook (won't work when running locally; use --novalidation)")
218-
validators.Create(mgr, f)
216+
setup.CreateWebhooks(mgr, f)
219217
}
220218

221-
// Create mutating admission controllers.
222-
setupLog.Info("Registering mutating webhook")
223-
mutators.Create(mgr)
224-
225219
// Create all reconciling controllers
226220
setupLog.Info("Creating controllers", "maxReconciles", maxReconciles)
227-
if err := reconcilers.Create(mgr, f, maxReconciles, false); err != nil {
221+
if err := setup.CreateReconcilers(mgr, f, maxReconciles, false); err != nil {
228222
setupLog.Error(err, "cannot create controllers")
229223
os.Exit(1)
230224
}

config/webhook/manifests.yaml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,60 +80,60 @@ webhooks:
8080
service:
8181
name: webhook-service
8282
namespace: system
83-
path: /validate-hnc-x-k8s-io-v1alpha2-hncconfigurations
83+
path: /validate-objects
8484
failurePolicy: Fail
85-
name: hncconfigurations.hnc.x-k8s.io
85+
name: objects.hnc.x-k8s.io
8686
rules:
8787
- apiGroups:
88-
- hnc.x-k8s.io
88+
- '*'
8989
apiVersions:
90-
- v1alpha2
90+
- '*'
9191
operations:
9292
- CREATE
9393
- UPDATE
9494
- DELETE
9595
resources:
96-
- hncconfigurations
96+
- '*'
9797
sideEffects: None
9898
- admissionReviewVersions:
9999
- v1
100100
clientConfig:
101101
service:
102102
name: webhook-service
103103
namespace: system
104-
path: /validate-v1-namespace
104+
path: /validate-hnc-x-k8s-io-v1alpha2-hncconfigurations
105105
failurePolicy: Fail
106-
name: namespaces.hnc.x-k8s.io
106+
name: hncconfigurations.hnc.x-k8s.io
107107
rules:
108108
- apiGroups:
109-
- ""
109+
- hnc.x-k8s.io
110110
apiVersions:
111-
- v1
111+
- v1alpha2
112112
operations:
113-
- DELETE
114113
- CREATE
115114
- UPDATE
115+
- DELETE
116116
resources:
117-
- namespaces
117+
- hncconfigurations
118118
sideEffects: None
119119
- admissionReviewVersions:
120120
- v1
121121
clientConfig:
122122
service:
123123
name: webhook-service
124124
namespace: system
125-
path: /validate-objects
125+
path: /validate-v1-namespace
126126
failurePolicy: Fail
127-
name: objects.hnc.x-k8s.io
127+
name: namespaces.hnc.x-k8s.io
128128
rules:
129129
- apiGroups:
130-
- '*'
130+
- ""
131131
apiVersions:
132-
- '*'
132+
- v1
133133
operations:
134+
- DELETE
134135
- CREATE
135136
- UPDATE
136-
- DELETE
137137
resources:
138-
- '*'
138+
- namespaces
139139
sideEffects: None

internal/reconcilers/anchor.go renamed to internal/anchor/reconciler.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
*/
1515

16-
package reconcilers
16+
package anchor
1717

1818
import (
1919
"context"
@@ -33,17 +33,19 @@ import (
3333

3434
api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
3535
"sigs.k8s.io/hierarchical-namespaces/internal/config"
36+
"sigs.k8s.io/hierarchical-namespaces/internal/crd"
3637
"sigs.k8s.io/hierarchical-namespaces/internal/forest"
38+
"sigs.k8s.io/hierarchical-namespaces/internal/logutils"
3739
"sigs.k8s.io/hierarchical-namespaces/internal/metadata"
3840
)
3941

40-
// AnchorReconciler reconciles SubnamespaceAnchor CRs to make sure all the subnamespaces are
42+
// Reconciler reconciles SubnamespaceAnchor CRs to make sure all the subnamespaces are
4143
// properly maintained.
42-
type AnchorReconciler struct {
44+
type Reconciler struct {
4345
client.Client
4446
Log logr.Logger
4547

46-
forest *forest.Forest
48+
Forest *forest.Forest
4749

4850
// Affected is a channel of event.GenericEvent (see "Watching Channels" in
4951
// https://book-v1.book.kubebuilder.io/beyond_basics/controller_watches.html) that is used to
@@ -53,8 +55,8 @@ type AnchorReconciler struct {
5355

5456
// Reconcile sets up some basic variables and then calls the business logic. It currently
5557
// only handles the creation of the namespaces but no deletion or state reporting yet.
56-
func (r *AnchorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
57-
log := loggerWithRID(r.Log).WithValues("trigger", req.NamespacedName)
58+
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
59+
log := logutils.WithRID(r.Log).WithValues("trigger", req.NamespacedName)
5860
log.V(1).Info("Reconciling anchor")
5961

6062
// Get names of the hierarchical namespace and the current namespace.
@@ -134,7 +136,7 @@ func (r *AnchorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
134136
// There are several conditions where we skip step 1 - for example, if we're uninstalling HNC, or
135137
// if allowCascadingDeletion is disabled but the subnamespace has descendants (see
136138
// shouldDeleteSubns for details). In such cases, we move straight to step 2.
137-
func (r *AnchorReconciler) onDeleting(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) (bool, error) {
139+
func (r *Reconciler) onDeleting(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) (bool, error) {
138140
// Early exit and continue reconciliation if the instance is not being deleted.
139141
if inst.DeletionTimestamp.IsZero() {
140142
return false, nil
@@ -143,7 +145,7 @@ func (r *AnchorReconciler) onDeleting(ctx context.Context, log logr.Logger, inst
143145
// We handle deletions differently depending on whether _one_ anchor is being deleted (i.e., the
144146
// user wants to delete the namespace) or whether the Anchor CRD is being deleted, which usually
145147
// means HNC is being uninstalled and we shouldn't delete _any_ namespaces.
146-
deletingCRD, err := isDeletingCRD(ctx, api.Anchors)
148+
deletingCRD, err := crd.IsDeletingCRD(ctx, api.Anchors)
147149
if err != nil {
148150
log.Error(err, "Couldn't determine if CRD is being deleted")
149151
return false, err
@@ -180,9 +182,9 @@ func (r *AnchorReconciler) onDeleting(ctx context.Context, log logr.Logger, inst
180182
//
181183
// This is the only part of the deletion process that needs to access the forest, in order to check
182184
// the recursive AllowCascadingDeletion setting.
183-
func (r *AnchorReconciler) shouldDeleteSubns(log logr.Logger, inst *api.SubnamespaceAnchor, nsInst *corev1.Namespace, deletingCRD bool) bool {
184-
r.forest.Lock()
185-
defer r.forest.Unlock()
185+
func (r *Reconciler) shouldDeleteSubns(log logr.Logger, inst *api.SubnamespaceAnchor, nsInst *corev1.Namespace, deletingCRD bool) bool {
186+
r.Forest.Lock()
187+
defer r.Forest.Unlock()
186188

187189
// If the CRD is being deleted, we want to leave the subnamespace alone.
188190
if deletingCRD {
@@ -211,7 +213,7 @@ func (r *AnchorReconciler) shouldDeleteSubns(log logr.Logger, inst *api.Subnames
211213
// if ACD=true on one of their ancestors; the webhooks *should* ensure that this is always true
212214
// before we get here, but if something slips by, we'll just leave the old subnamespace alone
213215
// with a missing-anchor condition.
214-
cns := r.forest.Get(inst.Name)
216+
cns := r.Forest.Get(inst.Name)
215217
if cns.ChildNames() != nil && !cns.AllowsCascadingDeletion() {
216218
log.Info("This subnamespace has descendants and allowCascadingDeletion is disabled; will not delete")
217219
return false
@@ -244,7 +246,7 @@ func (r *AnchorReconciler) shouldDeleteSubns(log logr.Logger, inst *api.Subnames
244246
// shouldFinalizeAnchor determines whether the anchor is safe to delete. It should only be called once
245247
// we know that we don't need to delete the subnamespace itself (e.g. it's already gone, it can't be
246248
// deleted, it's in the process of being deleted, etc).
247-
func (r *AnchorReconciler) shouldFinalizeAnchor(log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) bool {
249+
func (r *Reconciler) shouldFinalizeAnchor(log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) bool {
248250
// If the anchor is already finalized, there's no need to do it again.
249251
if len(inst.ObjectMeta.Finalizers) == 0 {
250252
return false
@@ -289,7 +291,7 @@ func (r *AnchorReconciler) shouldFinalizeAnchor(log logr.Logger, inst *api.Subna
289291
}
290292
}
291293

292-
func (r *AnchorReconciler) updateState(log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) {
294+
func (r *Reconciler) updateState(log logr.Logger, inst *api.SubnamespaceAnchor, snsInst *corev1.Namespace) {
293295
pnm := inst.Namespace
294296
sOf := snsInst.Annotations[api.SubnamespaceOf]
295297
switch {
@@ -308,9 +310,9 @@ func (r *AnchorReconciler) updateState(log logr.Logger, inst *api.SubnamespaceAn
308310
}
309311
}
310312

311-
// It enqueues a subnamespace anchor for later reconciliation. This occurs in a goroutine
313+
// Enqueue enqueues a subnamespace anchor for later reconciliation. This occurs in a goroutine
312314
// so the caller doesn't block; since the reconciler is never garbage-collected, this is safe.
313-
func (r *AnchorReconciler) enqueue(log logr.Logger, nm, pnm, reason string) {
315+
func (r *Reconciler) Enqueue(log logr.Logger, nm, pnm, reason string) {
314316
go func() {
315317
// The watch handler doesn't care about anything except the metadata.
316318
inst := &api.SubnamespaceAnchor{}
@@ -321,7 +323,7 @@ func (r *AnchorReconciler) enqueue(log logr.Logger, nm, pnm, reason string) {
321323
}()
322324
}
323325

324-
func (r *AnchorReconciler) getInstance(ctx context.Context, pnm, nm string) (*api.SubnamespaceAnchor, error) {
326+
func (r *Reconciler) getInstance(ctx context.Context, pnm, nm string) (*api.SubnamespaceAnchor, error) {
325327
nsn := types.NamespacedName{Namespace: pnm, Name: nm}
326328
inst := &api.SubnamespaceAnchor{}
327329
if err := r.Get(ctx, nsn, inst); err != nil {
@@ -330,7 +332,7 @@ func (r *AnchorReconciler) getInstance(ctx context.Context, pnm, nm string) (*ap
330332
return inst, nil
331333
}
332334

333-
func (r *AnchorReconciler) writeInstance(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor) error {
335+
func (r *Reconciler) writeInstance(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor) error {
334336
if inst.CreationTimestamp.IsZero() {
335337
if err := r.Create(ctx, inst); err != nil {
336338
log.Error(err, "while creating on apiserver")
@@ -347,7 +349,7 @@ func (r *AnchorReconciler) writeInstance(ctx context.Context, log logr.Logger, i
347349

348350
// deleteInstance deletes the anchor instance. Note: Make sure there's no
349351
// finalizers on the instance before calling this function.
350-
func (r *AnchorReconciler) deleteInstance(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor) error {
352+
func (r *Reconciler) deleteInstance(ctx context.Context, log logr.Logger, inst *api.SubnamespaceAnchor) error {
351353
if err := r.Delete(ctx, inst); err != nil {
352354
return fmt.Errorf("while deleting on apiserver: %w", err)
353355
}
@@ -357,7 +359,7 @@ func (r *AnchorReconciler) deleteInstance(ctx context.Context, log logr.Logger,
357359
// getNamespace returns the namespace if it exists, or returns an invalid, blank, unnamed one if it
358360
// doesn't. This allows it to be trivially identified as a namespace that doesn't exist, and also
359361
// allows us to easily modify it if we want to create it.
360-
func (r *AnchorReconciler) getNamespace(ctx context.Context, nm string) (*corev1.Namespace, error) {
362+
func (r *Reconciler) getNamespace(ctx context.Context, nm string) (*corev1.Namespace, error) {
361363
ns := &corev1.Namespace{}
362364
nnm := types.NamespacedName{Name: nm}
363365
if err := r.Get(ctx, nnm, ns); err != nil {
@@ -369,7 +371,7 @@ func (r *AnchorReconciler) getNamespace(ctx context.Context, nm string) (*corev1
369371
return ns, nil
370372
}
371373

372-
func (r *AnchorReconciler) writeNamespace(ctx context.Context, log logr.Logger, nm, pnm string) error {
374+
func (r *Reconciler) writeNamespace(ctx context.Context, log logr.Logger, nm, pnm string) error {
373375
inst := &corev1.Namespace{}
374376
inst.ObjectMeta.Name = nm
375377
metadata.SetAnnotation(inst, api.SubnamespaceOf, pnm)
@@ -386,15 +388,15 @@ func (r *AnchorReconciler) writeNamespace(ctx context.Context, log logr.Logger,
386388
return nil
387389
}
388390

389-
func (r *AnchorReconciler) deleteNamespace(ctx context.Context, log logr.Logger, inst *corev1.Namespace) error {
391+
func (r *Reconciler) deleteNamespace(ctx context.Context, log logr.Logger, inst *corev1.Namespace) error {
390392
if err := r.Delete(ctx, inst); err != nil {
391393
log.Error(err, "While deleting subnamespace")
392394
return err
393395
}
394396
return nil
395397
}
396398

397-
func (r *AnchorReconciler) SetupWithManager(mgr ctrl.Manager) error {
399+
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
398400
// Maps an subnamespace to its anchor in the parent namespace.
399401
nsMapFn := func(obj client.Object) []reconcile.Request {
400402
if obj.GetAnnotations()[api.SubnamespaceOf] == "" {

0 commit comments

Comments
 (0)