Skip to content

Commit dae149d

Browse files
fanminshiShawn Hurley
authored andcommitted
pkg/refactor: add controller_kind_test.go and controller_test.go
1 parent 067e285 commit dae149d

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

pkg/scaffold/controller_kind_test.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package scaffold
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/sergi/go-diff/diffmatchpatch"
8+
)
9+
10+
func TestControllerKind(t *testing.T) {
11+
r, err := NewResource(appApiVersion, appKind)
12+
if err != nil {
13+
t.Fatal(err)
14+
}
15+
codegen := NewControllerKindCodegen(&ControllerKindInput{ProjectPath: appProjectPath, Resource: r})
16+
buf := &bytes.Buffer{}
17+
if err := codegen.Render(buf); err != nil {
18+
t.Fatal(err)
19+
}
20+
if controllerKindExp != buf.String() {
21+
dmp := diffmatchpatch.New()
22+
diffs := diffmatchpatch.New().DiffMain(controllerKindExp, buf.String(), false)
23+
t.Fatalf("expected vs actual differs. Red text is missing and green text is extra.\n%v", dmp.DiffPrettyText(diffs))
24+
}
25+
}
26+
27+
const controllerKindExp = `package appservice
28+
29+
import (
30+
"context"
31+
"log"
32+
33+
appv1alpha1 "github.com/example-inc/app-operator/pkg/apis/app/v1alpha1"
34+
35+
corev1 "k8s.io/api/core/v1"
36+
"k8s.io/apimachinery/pkg/api/errors"
37+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38+
"k8s.io/apimachinery/pkg/runtime"
39+
"k8s.io/apimachinery/pkg/types"
40+
"sigs.k8s.io/controller-runtime/pkg/client"
41+
"sigs.k8s.io/controller-runtime/pkg/controller"
42+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
43+
"sigs.k8s.io/controller-runtime/pkg/handler"
44+
"sigs.k8s.io/controller-runtime/pkg/manager"
45+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
46+
"sigs.k8s.io/controller-runtime/pkg/source"
47+
)
48+
49+
/**
50+
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
51+
* business logic. Delete these comments after modifying this file.*
52+
*/
53+
54+
// Add creates a new AppService Controller and adds it to the Manager. The Manager will set fields on the Controller
55+
// and Start it when the Manager is Started.
56+
func Add(mgr manager.Manager) error {
57+
return add(mgr, newReconciler(mgr))
58+
}
59+
60+
// newReconciler returns a new reconcile.Reconciler
61+
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
62+
return &ReconcileAppService{client: mgr.GetClient(), scheme: mgr.GetScheme()}
63+
}
64+
65+
// add adds a new Controller to mgr with r as the reconcile.Reconciler
66+
func add(mgr manager.Manager, r reconcile.Reconciler) error {
67+
// Create a new controller
68+
c, err := controller.New("appservice-controller", mgr, controller.Options{Reconciler: r})
69+
if err != nil {
70+
return err
71+
}
72+
73+
// Watch for changes to primary resource AppService
74+
err = c.Watch(&source.Kind{Type: &appv1alpha1.AppService{}}, &handler.EnqueueRequestForObject{})
75+
if err != nil {
76+
return err
77+
}
78+
79+
// TODO(user): Modify this to be the types you create that are owned by the primary resource
80+
// Watch for changes to secondary resource Pods and requeue the owner AppService
81+
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
82+
IsController: true,
83+
OwnerType: &appv1alpha1.AppService{},
84+
})
85+
if err != nil {
86+
return err
87+
}
88+
89+
return nil
90+
}
91+
92+
var _ reconcile.Reconciler = &ReconcileAppService{}
93+
94+
// ReconcileAppService reconciles a AppService object
95+
type ReconcileAppService struct {
96+
// TODO: Clarify the split client
97+
// This client, initialized using mgr.Client() above, is a split client
98+
// that reads objects from the cache and writes to the apiserver
99+
client client.Client
100+
scheme *runtime.Scheme
101+
}
102+
103+
// Reconcile reads that state of the cluster for a AppService object and makes changes based on the state read
104+
// and what is in the AppService.Spec
105+
// TODO(user): Modify this Reconcile function to implement your Controller logic. This example creates
106+
// a Pod as an example
107+
// Note:
108+
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
109+
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
110+
func (r *ReconcileAppService) Reconcile(request reconcile.Request) (reconcile.Result, error) {
111+
log.Printf("Reconciling AppService %s/%s\n", request.Namespace, request.Name)
112+
113+
// Fetch the AppService instance
114+
instance := &appv1alpha1.AppService{}
115+
err := r.client.Get(context.TODO(), request.NamespacedName, instance)
116+
if err != nil {
117+
if errors.IsNotFound(err) {
118+
// Request object not found, could have been deleted after reconcile request.
119+
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
120+
// Return and don't requeue
121+
return reconcile.Result{}, nil
122+
}
123+
// Error reading the object - requeue the request.
124+
return reconcile.Result{}, err
125+
}
126+
127+
// Define a new Pod object
128+
pod := newPodForCR(instance)
129+
130+
// Set AppService instance as the owner and controller
131+
if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil {
132+
return reconcile.Result{}, err
133+
}
134+
135+
// Check if this Pod already exists
136+
found := &corev1.Pod{}
137+
err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found)
138+
if err != nil && errors.IsNotFound(err) {
139+
log.Printf("Creating a new Pod %s/%s\n", pod.Namespace, pod.Name)
140+
err = r.client.Create(context.TODO(), pod)
141+
if err != nil {
142+
return reconcile.Result{}, err
143+
}
144+
145+
// Pod created successfully - don't requeue
146+
return reconcile.Result{}, nil
147+
} else if err != nil {
148+
return reconcile.Result{}, err
149+
}
150+
151+
// Pod already exists - don't requeue
152+
log.Printf("Skip reconcile: Pod %s/%s already exists", found.Namespace, found.Name)
153+
return reconcile.Result{}, nil
154+
}
155+
156+
// newPodForCR returns a busybox pod with the same name/namespace as the cr
157+
func newPodForCR(cr *appv1alpha1.AppService) *corev1.Pod {
158+
labels := map[string]string{
159+
"app": cr.Name,
160+
}
161+
return &corev1.Pod{
162+
ObjectMeta: metav1.ObjectMeta{
163+
Name: cr.Name + "-pod",
164+
Namespace: cr.Namespace,
165+
Labels: labels,
166+
},
167+
Spec: corev1.PodSpec{
168+
Containers: []corev1.Container{
169+
{
170+
Name: "busybox",
171+
Image: "busybox",
172+
Command: []string{"sleep", "3600"},
173+
},
174+
},
175+
},
176+
}
177+
}
178+
`

pkg/scaffold/controller_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package scaffold
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/sergi/go-diff/diffmatchpatch"
8+
)
9+
10+
func TestController(t *testing.T) {
11+
codegen := NewControllerCodegen()
12+
buf := &bytes.Buffer{}
13+
if err := codegen.Render(buf); err != nil {
14+
t.Fatal(err)
15+
}
16+
if controllerExp != buf.String() {
17+
dmp := diffmatchpatch.New()
18+
diffs := diffmatchpatch.New().DiffMain(controllerKindExp, buf.String(), false)
19+
t.Fatalf("expected vs actual differs. Red text is missing and green text is extra.\n%v", dmp.DiffPrettyText(diffs))
20+
}
21+
}
22+
23+
const controllerExp = `package controller
24+
25+
import (
26+
"sigs.k8s.io/controller-runtime/pkg/manager"
27+
)
28+
29+
// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
30+
var AddToManagerFuncs []func(manager.Manager) error
31+
32+
// AddToManager adds all Controllers to the Manager
33+
func AddToManager(m manager.Manager) error {
34+
for _, f := range AddToManagerFuncs {
35+
if err := f(m); err != nil {
36+
return err
37+
}
38+
}
39+
return nil
40+
}
41+
`

0 commit comments

Comments
 (0)