这是github上client-go repo中关于thirdpartresource的实例。
主要使用了clientset 和restclient两种接口,通过对资源的定义以及资源实例的定义、注册,实现自定义资源加入自定义thirdpartresource。
package main
import (
"flag"
"fmt"
// "encoding/json"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/errors"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
metav1 "k8s.io/client-go/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/runtime"
"k8s.io/client-go/pkg/runtime/schema"
"k8s.io/client-go/pkg/runtime/serializer"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/pkg/api/meta"
// Only required to authenticate against GKE clusters
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)
var (
config *rest.Config
)
func main() {
kubeconfig := flag.String("kubeconfig", "./config", "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.
// 判断是否制定kubeconfig 否则通过incluster方式启动
config, err := buildConfig(*kubeconfig)
if err != nil {
panic(err)
}
//返回Clientset
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", metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// 定义ThirdPartyResource
tpr := &v1beta1.ThirdPartyResource{
ObjectMeta: v1.ObjectMeta{
//定义元数据名称
Name: "example.k8s.io",
},
Versions: []v1beta1.APIVersion{
//定义versions
{Name: "v1"},
},
//描述信息
Description: "An Example ThirdPartyResource",
}
//创建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
//按照restclient的要求增加配置
configureClient(tprconfig)
// 创建restclient
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)
}
//用于判断是否位incluster
func buildConfig(kubeconfig string) (*rest.Config, error) {
if kubeconfig != "" {
return clientcmd.BuildConfigFromFlags("", kubeconfig)
}
return rest.InClusterConfig()
}
//相对于clientset和dynamicclient resetclient需要增加额外配置
func configureClient(config *rest.Config) {
groupversion := schema.GroupVersion{
Group: "k8s.io",
Version: "v1",
}
config.GroupVersion = &groupversion
// 指定访问的api接口,如果访问的是pods等正式版数据应访问/api
config.APIPath = "/apis"
config.ContentType = runtime.ContentTypeJSON
//指定序列化工厂函数
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs}
//添加数据对象到scheme
schemeBuilder := runtime.NewSchemeBuilder(
func(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(
groupversion,
&Example{},
&ExampleList{},
&api.ListOptions{},
&api.DeleteOptions{},
)
return nil
})
schemeBuilder.AddToScheme(api.Scheme)
}
//SPEC 信息
type ExampleSpec struct {
Foo string `json:"foo"`
Bar bool `json:"bar"`
}
//数据结构
type Example struct {
metav1.TypeMeta `json:",inline"`
Metadata api.ObjectMeta `json:"metadata"`
Spec ExampleSpec `json:"spec"`
}
type ExampleList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []Example `json:"items"`
}
//实现runtime.Object接口
// Required to satisfy Object interface,为request.Result.Into的数据类型
func (e *Example) GetObjectKind() schema.ObjectKind {
return &e.TypeMeta
}
//实现meta.ObjectMetaAccessor 用于设置填充metadata
// Required to satisfy ObjectMetaAccessor interface
func (e *Example) GetObjectMeta() meta.Object {
return &e.Metadata
}
// Required to satisfy Object interface
func (el *ExampleList) GetObjectKind() schema.ObjectKind {
return &el.TypeMeta
}
// Required to satisfy ListMetaAccessor interface
func (el *ExampleList) GetListMeta() metav1.List {
return &el.Metadata
}