diff --git a/examples/third-party-resources/main.go b/examples/third-party-resources/main.go new file mode 100644 index 00000000..9421e2f1 --- /dev/null +++ b/examples/third-party-resources/main.go @@ -0,0 +1,155 @@ +package main + +import ( + "flag" + "fmt" + + "k8s.io/client-go/1.5/kubernetes" + "k8s.io/client-go/1.5/pkg/api" + "k8s.io/client-go/1.5/pkg/api/errors" + "k8s.io/client-go/1.5/pkg/api/unversioned" + "k8s.io/client-go/1.5/pkg/api/v1" + "k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1" + "k8s.io/client-go/1.5/pkg/runtime" + "k8s.io/client-go/1.5/pkg/runtime/serializer" + "k8s.io/client-go/1.5/rest" + "k8s.io/client-go/1.5/tools/clientcmd" + + // Only required to authenticate against GKE clusters + _ "k8s.io/client-go/1.5/plugin/pkg/client/auth/gcp" +) + +var ( + config *rest.Config +) + +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) + } + + // initialize third party resource if it does not exist + tpr, err := clientset.Extensions().ThirdPartyResources().Get("example.k8s.io") + if err != nil { + if errors.IsNotFound(err) { + tpr := &v1beta1.ThirdPartyResource{ + ObjectMeta: v1.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) + } + 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: api.ObjectMeta{ + Name: "example1", + }, + Spec: ExampleSpec{ + Foo: "hello", + Bar: true, + }, + } + + var result Example + err = tprclient.Post(). + Resource("examples"). + Namespace(api.NamespaceDefault). + Body(example). + Do().Into(&result) + + if err != nil { + 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) +} + +func buildConfig(kubeconfig string) (*rest.Config, error) { + if kubeconfig != "" { + return clientcmd.BuildConfigFromFlags("", kubeconfig) + } + return rest.InClusterConfig() +} + +func configureClient(config *rest.Config) { + groupversion := unversioned.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{}, + &api.ListOptions{}, + &api.DeleteOptions{}, + ) + return nil + }) + schemeBuilder.AddToScheme(api.Scheme) +} diff --git a/examples/third-party-resources/types.go b/examples/third-party-resources/types.go new file mode 100644 index 00000000..c6dd2e1d --- /dev/null +++ b/examples/third-party-resources/types.go @@ -0,0 +1,77 @@ +package main + +import ( + "encoding/json" + + "k8s.io/client-go/1.5/pkg/api" + "k8s.io/client-go/1.5/pkg/api/meta" + "k8s.io/client-go/1.5/pkg/api/unversioned" +) + +type ExampleSpec struct { + Foo string `json:"foo"` + Bar bool `json:"bar"` +} + +type Example struct { + unversioned.TypeMeta `json:",inline"` + Metadata api.ObjectMeta `json:"metadata"` + + Spec ExampleSpec `json:"spec"` +} + +type ExampleList struct { + unversioned.TypeMeta `json:",inline"` + Metadata unversioned.ListMeta `json:"metadata"` + + Items []Example `json:"items"` +} + +// Required to satisfy Object interface +func (e *Example) GetObjectKind() unversioned.ObjectKind { + return &e.TypeMeta +} + +// Required to satisfy ObjectMetaAccessor interface +func (e *Example) GetObjectMeta() meta.Object { + return &e.Metadata +} + +// Required to satisfy Object interface +func (el *ExampleList) GetObjectKind() unversioned.ObjectKind { + return &el.TypeMeta +} + +// Required to satisfy ListMetaAccessor interface +func (el *ExampleList) GetListMeta() unversioned.List { + return &el.Metadata +} + +// The code below is used only to work around a known problem with third-party +// resources and ugorji. If/when these issues are resolved, the code below +// should no longer be required. + +type ExampleListCopy ExampleList +type ExampleCopy Example + +func (e *Example) UnmarshalJSON(data []byte) error { + tmp := ExampleCopy{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + tmp2 := Example(tmp) + *e = tmp2 + return nil +} + +func (el *ExampleList) UnmarshalJSON(data []byte) error { + tmp := ExampleListCopy{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + tmp2 := ExampleList(tmp) + *el = tmp2 + return nil +}