Skip to content

Commit 5e96f27

Browse files
authored
Merge pull request #148 from hasbro17/haseeb/add-example-handler
example: add memcached handler for user-guide
2 parents b278881 + 534fd3a commit 5e96f27

File tree

1 file changed

+154
-1
lines changed

1 file changed

+154
-1
lines changed
Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,154 @@
1-
// TODO
1+
package stub
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
7+
v1alpha1 "github.com/example-inc/memcached-operator/pkg/apis/cache/v1alpha1"
8+
9+
"github.com/coreos/operator-sdk/pkg/sdk/action"
10+
"github.com/coreos/operator-sdk/pkg/sdk/handler"
11+
"github.com/coreos/operator-sdk/pkg/sdk/query"
12+
"github.com/coreos/operator-sdk/pkg/sdk/types"
13+
apps_v1 "k8s.io/api/apps/v1"
14+
"k8s.io/api/core/v1"
15+
apierrors "k8s.io/apimachinery/pkg/api/errors"
16+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
"k8s.io/apimachinery/pkg/labels"
18+
)
19+
20+
func NewHandler() handler.Handler {
21+
return &Handler{}
22+
}
23+
24+
type Handler struct {
25+
}
26+
27+
func (h *Handler) Handle(ctx types.Context, event types.Event) error {
28+
switch o := event.Object.(type) {
29+
case *v1alpha1.Memcached:
30+
memcached := o
31+
32+
// Create the deployment if it doesn't exist
33+
dep := deploymentForMemcached(memcached)
34+
err := action.Create(dep)
35+
if err != nil && !apierrors.IsAlreadyExists(err) {
36+
return fmt.Errorf("failed to create deployment: %v", err)
37+
}
38+
39+
// Ensure the deployment size is the same as the spec
40+
err = query.Get(dep)
41+
if err != nil {
42+
return fmt.Errorf("failed to get deployment: %v", err)
43+
}
44+
size := memcached.Spec.Size
45+
if *dep.Spec.Replicas != size {
46+
dep.Spec.Replicas = &size
47+
err = action.Update(dep)
48+
if err != nil {
49+
return fmt.Errorf("failed to update deployment: %v", err)
50+
}
51+
}
52+
53+
// Update the Memcached status with the pod names
54+
podList := podList()
55+
labelSelector := labels.SelectorFromSet(labelsForMemcached(memcached.Name)).String()
56+
listOps := &metav1.ListOptions{LabelSelector: labelSelector}
57+
err = query.List(memcached.Namespace, podList, query.WithListOptions(listOps))
58+
if err != nil {
59+
return fmt.Errorf("failed to list pods: %v", err)
60+
}
61+
podNames := getPodNames(podList.Items)
62+
if !reflect.DeepEqual(podNames, memcached.Status.Nodes) {
63+
memcached.Status.Nodes = podNames
64+
err := action.Update(memcached)
65+
if err != nil {
66+
return fmt.Errorf("failed to update memcached status: %v", err)
67+
}
68+
}
69+
}
70+
return nil
71+
}
72+
73+
// deploymentForMemcached returns a memcached Deployment object
74+
func deploymentForMemcached(m *v1alpha1.Memcached) *apps_v1.Deployment {
75+
ls := labelsForMemcached(m.Name)
76+
replicas := m.Spec.Size
77+
78+
dep := &apps_v1.Deployment{
79+
TypeMeta: metav1.TypeMeta{
80+
APIVersion: "apps/v1",
81+
Kind: "Deployment",
82+
},
83+
ObjectMeta: metav1.ObjectMeta{
84+
Name: m.Name,
85+
Namespace: m.Namespace,
86+
},
87+
Spec: apps_v1.DeploymentSpec{
88+
Replicas: &replicas,
89+
Selector: &metav1.LabelSelector{
90+
MatchLabels: ls,
91+
},
92+
Template: v1.PodTemplateSpec{
93+
ObjectMeta: metav1.ObjectMeta{
94+
Labels: ls,
95+
},
96+
Spec: v1.PodSpec{
97+
Containers: []v1.Container{{
98+
Image: "memcached:1.4.36-alpine",
99+
Name: "memcached",
100+
Command: []string{"memcached", "-m=64", "-o", "modern", "-v"},
101+
Ports: []v1.ContainerPort{{
102+
ContainerPort: 11211,
103+
Name: "memcached",
104+
}},
105+
}},
106+
},
107+
},
108+
},
109+
}
110+
addOwnerRefToObject(dep, asOwner(m))
111+
return dep
112+
}
113+
114+
// labelsForMemcached returns the labels for selecting the resources
115+
// belonging to the given memcached CR name.
116+
func labelsForMemcached(name string) map[string]string {
117+
return map[string]string{"app": "memcached", "memcached_cr": name}
118+
}
119+
120+
// addOwnerRefToObject appends the desired OwnerReference to the object
121+
func addOwnerRefToObject(obj metav1.Object, ownerRef metav1.OwnerReference) {
122+
obj.SetOwnerReferences(append(obj.GetOwnerReferences(), ownerRef))
123+
}
124+
125+
// asOwner returns an OwnerReference set as the memcached CR
126+
func asOwner(m *v1alpha1.Memcached) metav1.OwnerReference {
127+
trueVar := true
128+
return metav1.OwnerReference{
129+
APIVersion: m.APIVersion,
130+
Kind: m.Kind,
131+
Name: m.Name,
132+
UID: m.UID,
133+
Controller: &trueVar,
134+
}
135+
}
136+
137+
// podList returns a v1.PodList object
138+
func podList() *v1.PodList {
139+
return &v1.PodList{
140+
TypeMeta: metav1.TypeMeta{
141+
Kind: "Pod",
142+
APIVersion: "v1",
143+
},
144+
}
145+
}
146+
147+
// getPodNames returns the pod names of the array of pods passed in
148+
func getPodNames(pods []v1.Pod) []string {
149+
var podNames []string
150+
for _, pod := range pods {
151+
podNames = append(podNames, pod.Name)
152+
}
153+
return podNames
154+
}

0 commit comments

Comments
 (0)