Skip to content

Commit 66b532b

Browse files
authored
Merge pull request #1 from metacontroller/setup
chore: Initial commit
2 parents 6ecd307 + 8640b46 commit 66b532b

11 files changed

+425
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
thing-controller

Dockerfile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM golang:1.19 AS build
2+
3+
COPY . /go/src/thing-controller
4+
WORKDIR /go/src/thing-controller
5+
RUN go mod vendor && go build -o /go/bin/thing-controller
6+
7+
FROM debian:stretch-slim
8+
9+
COPY --from=build /go/bin/thing-controller /usr/bin/thing-controller

Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
PWD := ${CURDIR}
2+
ADDITIONAL_BUILD_ARGUMENTS?=""
3+
4+
PKG := metacontroller
5+
API_GROUPS := metacontroller/v1alpha1
6+
7+
CODE_GENERATOR_VERSION="v0.24.3"
8+
9+
all: generate_crds
10+
11+
.PHONY: generate_crds
12+
generate_crds:
13+
@echo "+ Generating crds"
14+
@go install sigs.k8s.io/controller-tools/cmd/controller-gen@latest
15+
@controller-gen +crd:generateEmbeddedObjectMeta=true +paths="./api/..." +output:crd:stdout > crdv1.yaml

README.md

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Example Go Controller
2+
3+
This controller doesn't do anything useful.
4+
It's just an example skeleton for writing Metacontroller hooks with Go.
5+
6+
**WARNING**
7+
8+
There's a [known issue](https://github.com/GoogleCloudPlatform/metacontroller/issues/76)
9+
that makes it difficult to produce JSON according to the rules that Metacontroller
10+
requires if you import the official Go structs for Kubernetes APIs.
11+
In particular, some fields will always be emitted, even if you never set them,
12+
which goes against Metacontroller's [apply semantics](https://metacontroller.github.io/metacontroller/api/apply/).
13+
14+
### Prerequisites
15+
16+
* [Install Metacontroller](https://metacontroller.github.io/metacontroller/guide/install.html)
17+
18+
### Install Thing Controller
19+
20+
```sh
21+
kubectl apply -f crdv1.yaml
22+
kubectl apply -f thing-controller.yaml
23+
```
24+
25+
### Create a Thing
26+
27+
```sh
28+
kubectl apply -f my-thing.yaml
29+
```
30+
31+
Look at the thing:
32+
33+
```sh
34+
kubectl get thing -o yaml
35+
```
36+
37+
Look at the thing the thing created:
38+
39+
```sh
40+
kubectl get pod thing-1 -a
41+
```
42+
43+
Look at what the thing the thing created said:
44+
45+
```sh
46+
kubectl logs thing-1
47+
```
48+
49+
### Clean up
50+
51+
```sh
52+
kubectl delete -f thing-controller.yaml
53+
```
54+
55+
### Building
56+
57+
You don't need to build to run the example above,
58+
but if you make changes:
59+
60+
```sh
61+
go mod vendor
62+
go build -o thing-controller
63+
```
64+
65+
Or just make a new container image:
66+
67+
```sh
68+
docker build . -t thing-controller
69+
```

api/types.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* Copyright 2022. Metacontroller authors.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
* /
15+
*/
16+
17+
// +groupName=ctl.enisoc.com
18+
package v1
19+
20+
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
type ThingSpec struct {
23+
message string `json:"message"`
24+
}
25+
26+
// Thing
27+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
28+
// +kubebuilder:subresource:status
29+
// +kubebuilder:resource:path=things,scope=Namespaced
30+
type Thing struct {
31+
metav1.TypeMeta `json:",inline"`
32+
metav1.ObjectMeta `json:"metadata"`
33+
34+
Spec ThingSpec `json:"spec"`
35+
}

crdv1.yaml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.10.0
7+
creationTimestamp: null
8+
name: things.ctl.enisoc.com
9+
spec:
10+
group: ctl.enisoc.com
11+
names:
12+
kind: Thing
13+
listKind: ThingList
14+
plural: things
15+
singular: thing
16+
scope: Namespaced
17+
versions:
18+
- name: v1
19+
schema:
20+
openAPIV3Schema:
21+
description: Thing
22+
properties:
23+
apiVersion:
24+
description: 'APIVersion defines the versioned schema of this representation
25+
of an object. Servers should convert recognized schemas to the latest
26+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
27+
type: string
28+
kind:
29+
description: 'Kind is a string value representing the REST resource this
30+
object represents. Servers may infer this from the endpoint the client
31+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
32+
type: string
33+
metadata:
34+
type: object
35+
spec:
36+
properties:
37+
message:
38+
type: string
39+
required:
40+
- message
41+
type: object
42+
required:
43+
- metadata
44+
- spec
45+
type: object
46+
served: true
47+
storage: true
48+
subresources:
49+
status: {}

go.mod

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module thing-controller
2+
3+
go 1.19
4+
5+
require (
6+
k8s.io/api v0.0.0-20180308023924-fd252c3a3e1d
7+
k8s.io/apimachinery v0.0.0-20180302183502-e9ff529c66f8
8+
)
9+
10+
require (
11+
github.com/ghodss/yaml v1.0.0 // indirect
12+
github.com/gogo/protobuf v1.0.0 // indirect
13+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
14+
github.com/google/gofuzz v1.0.0 // indirect
15+
github.com/json-iterator/go v1.1.12 // indirect
16+
github.com/spf13/pflag v1.0.0 // indirect
17+
github.com/stretchr/testify v1.8.1 // indirect
18+
golang.org/x/net v0.0.0-20180308154319-d0aafc73d5cd // indirect
19+
golang.org/x/text v0.3.0 // indirect
20+
gopkg.in/inf.v0 v0.9.0 // indirect
21+
gopkg.in/yaml.v2 v2.4.0 // indirect
22+
)

go.sum

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
5+
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
6+
github.com/gogo/protobuf v1.0.0 h1:2jyBKDKU/8v3v2xVR2PtiWQviFUyiaGk2rpfyFT8rTM=
7+
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
8+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
9+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
10+
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
11+
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
12+
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
13+
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
14+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
15+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
16+
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
17+
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
18+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
19+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
20+
github.com/spf13/pflag v1.0.0 h1:oaPbdDe/x0UncahuwiPxW1GYJyilRAdsPnq3e1yaPcI=
21+
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
22+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
23+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
24+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
25+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
26+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
27+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
28+
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
29+
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
30+
golang.org/x/net v0.0.0-20180308154319-d0aafc73d5cd h1:GNzbLJRy/nHOFS5m5780xbL4nia5w6cyb8exQGYw3Z4=
31+
golang.org/x/net v0.0.0-20180308154319-d0aafc73d5cd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
32+
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
33+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
34+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
35+
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
36+
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
37+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
38+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
39+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
40+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
41+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
42+
k8s.io/api v0.0.0-20180308023924-fd252c3a3e1d h1:82NkfZsgXdPC9a1nq0FsgF7OzZn8rWf/Vn8nv1XQYh4=
43+
k8s.io/api v0.0.0-20180308023924-fd252c3a3e1d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
44+
k8s.io/apimachinery v0.0.0-20180302183502-e9ff529c66f8 h1:asJjRiuBvuXsmTKz/8u9DombWmog9pdhOpyfk0n1agc=
45+
k8s.io/apimachinery v0.0.0-20180302183502-e9ff529c66f8/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=

main.go

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
*
3+
* Copyright 2022. Metacontroller authors.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package main
17+
18+
import (
19+
"io/ioutil"
20+
"log"
21+
"net/http"
22+
23+
v1 "k8s.io/api/core/v1"
24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
"k8s.io/apimachinery/pkg/runtime"
26+
"k8s.io/apimachinery/pkg/util/json"
27+
)
28+
29+
type Controller struct {
30+
metav1.TypeMeta `json:",inline"`
31+
metav1.ObjectMeta `json:"metadata"`
32+
Spec ControllerSpec `json:"spec"`
33+
Status ControllerStatus `json:"status"`
34+
}
35+
36+
type ControllerSpec struct {
37+
Message string `json:"message"`
38+
}
39+
40+
type ControllerStatus struct {
41+
Replicas int `json:"replicas"`
42+
Succeeded int `json:"succeeded"`
43+
}
44+
45+
type SyncRequest struct {
46+
Parent Controller `json:"parent"`
47+
Children SyncRequestChildren `json:"children"`
48+
}
49+
50+
type SyncRequestChildren struct {
51+
Pods map[string]*v1.Pod `json:"Pod.v1"`
52+
}
53+
54+
type SyncResponse struct {
55+
Status ControllerStatus `json:"status"`
56+
Children []runtime.Object `json:"children"`
57+
}
58+
59+
func sync(request *SyncRequest) (*SyncResponse, error) {
60+
response := &SyncResponse{}
61+
62+
// Compute status based on latest observed state.
63+
for _, pod := range request.Children.Pods {
64+
response.Status.Replicas++
65+
if pod.Status.Phase == v1.PodSucceeded {
66+
response.Status.Succeeded++
67+
}
68+
}
69+
70+
// Generate desired children.
71+
pod := &v1.Pod{
72+
TypeMeta: metav1.TypeMeta{
73+
APIVersion: "v1",
74+
Kind: "Pod",
75+
},
76+
ObjectMeta: metav1.ObjectMeta{
77+
Name: request.Parent.Name,
78+
},
79+
Spec: v1.PodSpec{
80+
RestartPolicy: v1.RestartPolicyOnFailure,
81+
Containers: []v1.Container{
82+
{
83+
Name: "hello",
84+
Image: "busybox",
85+
Command: []string{"echo", request.Parent.Spec.Message},
86+
},
87+
},
88+
},
89+
}
90+
response.Children = append(response.Children, pod)
91+
92+
return response, nil
93+
}
94+
95+
func syncHandler(w http.ResponseWriter, r *http.Request) {
96+
body, err := ioutil.ReadAll(r.Body)
97+
if err != nil {
98+
http.Error(w, err.Error(), http.StatusInternalServerError)
99+
return
100+
}
101+
request := &SyncRequest{}
102+
if err := json.Unmarshal(body, request); err != nil {
103+
http.Error(w, err.Error(), http.StatusBadRequest)
104+
return
105+
}
106+
response, err := sync(request)
107+
if err != nil {
108+
http.Error(w, err.Error(), http.StatusInternalServerError)
109+
return
110+
}
111+
body, err = json.Marshal(&response)
112+
if err != nil {
113+
http.Error(w, err.Error(), http.StatusInternalServerError)
114+
return
115+
}
116+
w.Header().Set("Content-Type", "application/json")
117+
w.Write(body)
118+
}
119+
120+
func main() {
121+
http.HandleFunc("/sync", syncHandler)
122+
123+
log.Fatal(http.ListenAndServe(":8080", nil))
124+
}

my-thing.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: ctl.enisoc.com/v1
2+
kind: Thing
3+
metadata:
4+
name: thing-1
5+
spec:
6+
message: Hello, World!

0 commit comments

Comments
 (0)