-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
252 lines (210 loc) · 6.11 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/golang/glog"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := flag.String("kubeconfig", "", "Path to a kube config. Only required if out-of-cluster.")
flag.Parse()
// Create the client config. Use kubeconfig if given, otherwise assume in-cluster.
config, err := buildConfig(*kubeconfig)
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
kind_created_here := false
// initialize third party resource if it does not exist
tpr, err := clientset.Extensions().ThirdPartyResources().Get("example.k8s.io", metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
tpr := &v1beta1.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{
Name: "example.k8s.io",
},
Versions: []v1beta1.APIVersion{
{Name: "v1"},
},
Description: "An Example ThirdPartyResource",
}
result, err := clientset.Extensions().ThirdPartyResources().Create(tpr)
if err != nil {
panic(err)
}
kind_created_here = true
fmt.Printf("CREATED: %#v\nFROM: %#v\n", result, tpr)
} else {
panic(err)
}
} else {
fmt.Printf("SKIPPING: already exists %#v\n", tpr)
}
// make a new config for our extension's API group, using the first config as a baseline
var tprconfig *rest.Config
tprconfig = config
configureClient(tprconfig)
tprclient, err := rest.RESTClientFor(tprconfig)
if err != nil {
panic(err)
}
var example Example
err = tprclient.Get().
Resource("examples").
Namespace(api.NamespaceDefault).
Name("example1").
Do().Into(&example)
if err != nil {
if errors.IsNotFound(err) {
// Create an instance of our TPR
example := &Example{
Metadata: v1.ObjectMeta{
Name: "example1",
},
Spec: ExampleSpec{
Foo: "hello",
Bar: true,
},
}
var result Example
req := tprclient.Post().
Resource("examples").
Namespace(api.NamespaceDefault).
Body(example)
err = req.
Do().Into(&result)
if err != nil {
if (kind_created_here) {
glog.Infoln("Probably because of delay issue noted in https://github.com/kubernetes/features/issues/95 ...")
}
glog.Fatalf("Unable to create example1 --- request=%#v, result=%#v, err=%#v", req, result, err)
panic(err)
}
fmt.Printf("CREATED: %#v\n", result)
} else {
panic(err)
}
} else {
fmt.Printf("GET: %#v\n", example)
}
// Fetch a list of our TPRs
exampleList := ExampleList{}
err = tprclient.Get().Resource("examples").Do().Into(&exampleList)
if err != nil {
panic(err)
}
fmt.Printf("LIST: %#v\n", exampleList)
fmt.Printf("Starting watch!\n")
watch(tprclient)
}
func buildConfig(kubeconfig string) (*rest.Config, error) {
if kubeconfig != "" {
return clientcmd.BuildConfigFromFlags("", kubeconfig)
}
return rest.InClusterConfig()
}
func configureClient(config *rest.Config) {
groupversion := schema.GroupVersion{
Group: "k8s.io",
Version: "v1",
}
config.GroupVersion = &groupversion
config.APIPath = "/apis"
config.ContentType = runtime.ContentTypeJSON
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs}
schemeBuilder := runtime.NewSchemeBuilder(
func(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(
groupversion,
&Example{},
&ExampleList{},
&v1.ListOptions{},
&v1.DeleteOptions{},
)
return nil
})
schemeBuilder.AddToScheme(api.Scheme)
}
func watch(client *rest.RESTClient) {
stop := make(chan struct{}, 1)
source := cache.NewListWatchFromClient(
client,
"examples",
api.NamespaceAll,
fields.Everything())
store, controller := cache.NewInformer(
source,
// The object type.
&Example{},
// resyncPeriod
// Every resyncPeriod, all resources in the cache will retrigger events.
// Set to 0 to disable the resync.
time.Second*60,
// Your custom resource event handlers.
cache.ResourceEventHandlerFuncs{
// Takes a single argument of type interface{}.
// Called on controller startup and when new resources are created.
AddFunc: create,
// Takes two arguments of type interface{}.
// Called on resource update and every resyncPeriod on existing resources.
UpdateFunc: update,
// Takes a single argument of type interface{}.
// Called on resource deletion.
DeleteFunc: delete,
})
// store can be used to List and Get
// NEVER modify objects from the store. It's a read-only, local cache.
fmt.Println("listing examples from store:")
for _, obj := range store.List() {
example := obj.(*Example)
// This will likely be empty the first run, but may not
fmt.Printf("%#v\n", example)
}
// the controller run starts the event processing loop
go controller.Run(stop)
// and now we block on a signal
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
s := <-signals
fmt.Printf("received signal %#v, exiting...\n", s)
close(stop)
os.Exit(0)
}
// Handler functions as per the controller above.
// Note the coercion of the interface{} into a pointer of the expected type.
func create(obj interface{}) {
example := obj.(*Example)
fmt.Println("CREATED:", printExample(example))
}
func update(old, new interface{}) {
oldExample := old.(*Example)
newExample := new.(*Example)
fmt.Printf("UPDATED:\n old: %s\n new: %s\n", printExample(oldExample), printExample(newExample))
}
func delete(obj interface{}) {
example := obj.(*Example)
fmt.Println("DELETED:", printExample(example))
}
// convenience functions
func printExample(example *Example) string {
return fmt.Sprintf("%s/%s, APIVersion: %s, Kind: %s, Value: %#v", example.Metadata.Namespace, example.Metadata.Name, example.APIVersion, example.Kind, example)
}