Skip to content

Commit

Permalink
Merge pull request #111 from erikgb/controller-v2
Browse files Browse the repository at this point in the history
feat: make SubNamespace controller reconcile v2alpha1 version
  • Loading branch information
zoetrope authored Dec 8, 2023
2 parents b633da3 + 2bf7e5a commit 38ea8a4
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 40 deletions.
1 change: 0 additions & 1 deletion api/accurate/v1/subnamespace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ type SubNamespaceSpec struct {
}

//+kubebuilder:object:root=true
//+kubebuilder:storageversion

// SubNamespace is the Schema for the subnamespaces API
type SubNamespace struct {
Expand Down
5 changes: 5 additions & 0 deletions api/accurate/v2alpha1/subnamespace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type SubNamespaceSpec struct {
}

//+kubebuilder:object:root=true
//+kubebuilder:storageversion
//+kubebuilder:subresource:status
//+genclient

Expand Down Expand Up @@ -61,3 +62,7 @@ type SubNamespaceList struct {
func init() {
SchemeBuilder.Register(&SubNamespace{}, &SubNamespaceList{})
}

const (
SubNamespaceConflict string = "Conflict"
)
4 changes: 2 additions & 2 deletions charts/accurate/templates/generated/crds.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions config/crd/bases/accurate.cybozu.com_subnamespaces.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions controllers/namespace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"path"
"reflect"

accuratev1 "github.com/cybozu-go/accurate/api/accurate/v1"
accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
Expand Down Expand Up @@ -101,7 +101,7 @@ func (r *NamespaceReconciler) propagateMeta(ctx context.Context, ns, parent *cor
}

if _, ok := ns.Labels[constants.LabelParent]; ok {
subNS := &accuratev1.SubNamespace{}
subNS := &accuratev2alpha1.SubNamespace{}
err := r.Get(ctx, types.NamespacedName{Name: ns.Name, Namespace: parent.Name}, subNS)
if err != nil {
if !apierrors.IsNotFound(err) {
Expand Down Expand Up @@ -385,7 +385,7 @@ func (r *NamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error {

return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Namespace{}).
Watches(&accuratev1.SubNamespace{}, handler.Funcs{
Watches(&accuratev2alpha1.SubNamespace{}, handler.Funcs{
CreateFunc: func(ctx context.Context, ev event.CreateEvent, q workqueue.RateLimitingInterface) {
subNSHandler(ev.Object, q)
},
Expand Down
4 changes: 2 additions & 2 deletions controllers/namespace_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"errors"
"time"

accuratev1 "github.com/cybozu-go/accurate/api/accurate/v1"
accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
"github.com/cybozu-go/accurate/pkg/indexing"
. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -529,7 +529,7 @@ var _ = Describe("Namespace controller", func() {
Expect(err).NotTo(HaveOccurred())

By("creating a SubNamespace for sub1 namespace")
sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
sn.Namespace = "root"
sn.Name = "sub1"
sn.Spec.Labels = map[string]string{
Expand Down
86 changes: 76 additions & 10 deletions controllers/subnamespace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ package controllers

import (
"context"
"encoding/json"
"fmt"
"time"

accuratev1 "github.com/cybozu-go/accurate/api/accurate/v1"
accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
accuratev2alpha1ac "github.com/cybozu-go/accurate/internal/applyconfigurations/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/workqueue"
kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
Expand All @@ -19,6 +25,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

const (
fieldOwner client.FieldOwner = "accurate-controller"
)

// SubNamespaceReconciler reconciles a SubNamespace object
type SubNamespaceReconciler struct {
client.Client
Expand All @@ -33,7 +43,7 @@ type SubNamespaceReconciler struct {
func (r *SubNamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)

sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
if err := r.Get(ctx, req.NamespacedName, sn); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
Expand All @@ -54,7 +64,7 @@ func (r *SubNamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, nil
}

func (r *SubNamespaceReconciler) finalize(ctx context.Context, sn *accuratev1.SubNamespace) error {
func (r *SubNamespaceReconciler) finalize(ctx context.Context, sn *accuratev2alpha1.SubNamespace) error {
if !controllerutil.ContainsFinalizer(sn, constants.Finalizer) {
return nil
}
Expand Down Expand Up @@ -89,7 +99,7 @@ DELETE:
return r.Update(ctx, sn)
}

func (r *SubNamespaceReconciler) reconcileNS(ctx context.Context, sn *accuratev1.SubNamespace) error {
func (r *SubNamespaceReconciler) reconcileNS(ctx context.Context, sn *accuratev2alpha1.SubNamespace) error {
logger := log.FromContext(ctx)

ns := &corev1.Namespace{}
Expand All @@ -110,14 +120,27 @@ func (r *SubNamespaceReconciler) reconcileNS(ctx context.Context, sn *accuratev1
logger.Info("created a sub namespace", "name", sn.Name)
}

if ns.Labels[constants.LabelParent] == sn.Namespace {
sn.Status = accuratev1.SubNamespaceOK
} else {
ac := accuratev2alpha1ac.SubNamespace(sn.Name, sn.Namespace).
WithStatus(
accuratev2alpha1ac.SubNamespaceStatus().
WithObservedGeneration(sn.Generation),
)

if ns.Labels[constants.LabelParent] != sn.Namespace {
logger.Info("a conflicting namespace already exists")
sn.Status = accuratev1.SubNamespaceConflict
ac.Status.WithConditions(
newStatusCondition(sn.Status.Conditions,
metav1.Condition{
Type: string(kstatus.ConditionStalled),
Status: metav1.ConditionTrue,
ObservedGeneration: sn.Generation,
Reason: accuratev2alpha1.SubNamespaceConflict,
Message: "Conflicting namespace already exists",
}),
)
}

return r.Update(ctx, sn)
return r.patchSubNamespaceStatus(ctx, ac)
}

// SetupWithManager sets up the controller with the Manager.
Expand All @@ -134,7 +157,7 @@ func (r *SubNamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error {
}

return ctrl.NewControllerManagedBy(mgr).
For(&accuratev1.SubNamespace{}).
For(&accuratev2alpha1.SubNamespace{}).
Watches(&corev1.Namespace{}, handler.Funcs{
UpdateFunc: func(ctx context.Context, ev event.UpdateEvent, q workqueue.RateLimitingInterface) {
if ev.ObjectNew.GetDeletionTimestamp() != nil {
Expand All @@ -148,3 +171,46 @@ func (r *SubNamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error {
}).
Complete(r)
}

func newStatusCondition(existingConditions []metav1.Condition, newCondition metav1.Condition) metav1.Condition {
existingCondition := meta.FindStatusCondition(existingConditions, newCondition.Type)
if existingCondition != nil && existingCondition.Status == newCondition.Status {
newCondition.LastTransitionTime = existingCondition.LastTransitionTime
}

if newCondition.LastTransitionTime.IsZero() {
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
}

return newCondition
}

func (r *SubNamespaceReconciler) patchSubNamespaceStatus(ctx context.Context, ac *accuratev2alpha1ac.SubNamespaceApplyConfiguration) error {
sn := &accuratev2alpha1.SubNamespace{
ObjectMeta: metav1.ObjectMeta{
Name: *ac.Name,
Namespace: *ac.Namespace,
},
}

encodedPatch, err := json.Marshal(ac)
if err != nil {
return err
}

return r.Status().Patch(ctx, sn, applyPatch{encodedPatch}, fieldOwner, client.ForceOwnership)
}

type applyPatch struct {
patch []byte
}

var _ client.Patch = applyPatch{}

func (p applyPatch) Type() types.PatchType {
return types.ApplyPatchType
}

func (p applyPatch) Data(_ client.Object) ([]byte, error) {
return p.patch, nil
}
44 changes: 24 additions & 20 deletions controllers/subnamespace_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"time"

accuratev1 "github.com/cybozu-go/accurate/api/accurate/v1"
accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -57,7 +57,7 @@ var _ = Describe("SubNamespace controller", func() {
err := k8sClient.Create(ctx, ns)
Expect(err).NotTo(HaveOccurred())

sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
sn.Namespace = "test1"
sn.Name = "test1-sub1"
sn.Finalizers = []string{constants.Finalizer}
Expand All @@ -72,14 +72,15 @@ var _ = Describe("SubNamespace controller", func() {

Expect(sub1.Labels).To(HaveKeyWithValue(constants.LabelCreatedBy, "accurate"))
Expect(sub1.Labels).To(HaveKeyWithValue(constants.LabelParent, "test1"))
Eventually(func() accuratev1.SubNamespaceStatus {
sn = &accuratev1.SubNamespace{}
Eventually(func() int64 {
sn = &accuratev2alpha1.SubNamespace{}
err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "test1", Name: "test1-sub1"}, sn)
if err != nil {
return ""
return 0
}
return sn.Status
}).Should(Equal(accuratev1.SubNamespaceOK))
return sn.Status.ObservedGeneration
}).Should(BeNumerically(">", 0))
Expect(sn.Status.Conditions).To(BeEmpty())

err = k8sClient.Delete(ctx, sn)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -105,19 +106,21 @@ var _ = Describe("SubNamespace controller", func() {
err = k8sClient.Create(ctx, ns2)
Expect(err).NotTo(HaveOccurred())

sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
sn.Namespace = "test2"
sn.Name = "test2-sub1"
err = k8sClient.Create(ctx, sn)
Expect(err).NotTo(HaveOccurred())

Eventually(func() accuratev1.SubNamespaceStatus {
sn = &accuratev1.SubNamespace{}
Eventually(func() int64 {
sn = &accuratev2alpha1.SubNamespace{}
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "test2", Name: "test2-sub1"}, sn); err != nil {
return ""
return 0
}
return sn.Status
}).Should(Equal(accuratev1.SubNamespaceConflict))
return sn.Status.ObservedGeneration
}).Should(BeNumerically(">", 0))
Expect(sn.Status.Conditions).To(HaveLen(1))
Expect(sn.Status.Conditions[0].Reason).To(Equal(accuratev2alpha1.SubNamespaceConflict))
})

It("should not delete a conflicting sub namespace", func() {
Expand All @@ -126,7 +129,7 @@ var _ = Describe("SubNamespace controller", func() {
err := k8sClient.Create(ctx, ns)
Expect(err).NotTo(HaveOccurred())

sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
sn.Namespace = "test3"
sn.Name = "test3-sub1"
sn.Finalizers = []string{constants.Finalizer}
Expand All @@ -143,14 +146,15 @@ var _ = Describe("SubNamespace controller", func() {
err = k8sClient.Update(ctx, sub1)
Expect(err).NotTo(HaveOccurred())

Eventually(func() accuratev1.SubNamespaceStatus {
sn = &accuratev1.SubNamespace{}
Eventually(func() []metav1.Condition {
sn = &accuratev2alpha1.SubNamespace{}
err = k8sClient.Get(ctx, client.ObjectKey{Namespace: "test3", Name: "test3-sub1"}, sn)
if err != nil {
return ""
return nil
}
return sn.Status
}).Should(Equal(accuratev1.SubNamespaceConflict))
return sn.Status.Conditions
}).Should(HaveLen(1))
Expect(sn.Status.Conditions[0].Reason).To(Equal(accuratev2alpha1.SubNamespaceConflict))

err = k8sClient.Delete(ctx, sn)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -170,7 +174,7 @@ var _ = Describe("SubNamespace controller", func() {
err := k8sClient.Create(ctx, ns)
Expect(err).NotTo(HaveOccurred())

sn := &accuratev1.SubNamespace{}
sn := &accuratev2alpha1.SubNamespace{}
sn.Namespace = "test4"
sn.Name = "test4-sub1"
err = k8sClient.Create(ctx, sn)
Expand Down

0 comments on commit 38ea8a4

Please sign in to comment.