You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
2.9 KiB
144 lines
2.9 KiB
package kubernetes |
|
|
|
import ( |
|
"context" |
|
"errors" |
|
"fmt" |
|
"path/filepath" |
|
"strings" |
|
|
|
"github.com/go-kratos/kratos/v2/config" |
|
v1 "k8s.io/api/core/v1" |
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
|
"k8s.io/client-go/kubernetes" |
|
"k8s.io/client-go/rest" |
|
"k8s.io/client-go/tools/clientcmd" |
|
) |
|
|
|
// Option is kubernetes option. |
|
type Option func(*options) |
|
|
|
type options struct { |
|
// kubernetes namespace |
|
Namespace string |
|
// kubernetes labelSelector example `app=test` |
|
LabelSelector string |
|
// kubernetes fieldSelector example `app=test` |
|
FieldSelector string |
|
// set KubeConfig out-of-cluster Use outside cluster |
|
KubeConfig string |
|
// set master url |
|
Master string |
|
} |
|
|
|
// Namespace with kubernetes namespace. |
|
func Namespace(ns string) Option { |
|
return func(o *options) { |
|
o.Namespace = ns |
|
} |
|
} |
|
|
|
// LabelSelector with kubernetes label selector. |
|
func LabelSelector(label string) Option { |
|
return func(o *options) { |
|
o.LabelSelector = label |
|
} |
|
} |
|
|
|
// FieldSelector with kubernetes field selector. |
|
func FieldSelector(field string) Option { |
|
return func(o *options) { |
|
o.FieldSelector = field |
|
} |
|
} |
|
|
|
// KubeConfig with kubernetes config. |
|
func KubeConfig(config string) Option { |
|
return func(o *options) { |
|
o.KubeConfig = config |
|
} |
|
} |
|
|
|
// Master with kubernetes master. |
|
func Master(master string) Option { |
|
return func(o *options) { |
|
o.Master = master |
|
} |
|
} |
|
|
|
type kube struct { |
|
opts options |
|
client *kubernetes.Clientset |
|
} |
|
|
|
// NewSource new a kubernetes config source. |
|
func NewSource(opts ...Option) config.Source { |
|
op := options{} |
|
for _, o := range opts { |
|
o(&op) |
|
} |
|
return &kube{ |
|
opts: op, |
|
} |
|
} |
|
|
|
func (k *kube) init() (err error) { |
|
var config *rest.Config |
|
if k.opts.KubeConfig != "" { |
|
if config, err = clientcmd.BuildConfigFromFlags(k.opts.Master, k.opts.KubeConfig); err != nil { |
|
return err |
|
} |
|
} else { |
|
if config, err = rest.InClusterConfig(); err != nil { |
|
return err |
|
} |
|
} |
|
if k.client, err = kubernetes.NewForConfig(config); err != nil { |
|
return err |
|
} |
|
return nil |
|
} |
|
|
|
func (k *kube) load() (kvs []*config.KeyValue, err error) { |
|
cmList, err := k.client. |
|
CoreV1(). |
|
ConfigMaps(k.opts.Namespace). |
|
List(context.Background(), metav1.ListOptions{ |
|
LabelSelector: k.opts.LabelSelector, |
|
FieldSelector: k.opts.FieldSelector, |
|
}) |
|
if err != nil { |
|
return nil, err |
|
} |
|
for _, cm := range cmList.Items { |
|
kvs = append(kvs, k.configMap(cm)...) |
|
} |
|
return kvs, nil |
|
} |
|
|
|
func (k *kube) configMap(cm v1.ConfigMap) (kvs []*config.KeyValue) { |
|
for name, val := range cm.Data { |
|
k := fmt.Sprintf("%s/%s/%s", k.opts.Namespace, cm.Name, name) |
|
|
|
kvs = append(kvs, &config.KeyValue{ |
|
Key: k, |
|
Value: []byte(val), |
|
Format: strings.TrimPrefix(filepath.Ext(k), "."), |
|
}) |
|
} |
|
return kvs |
|
} |
|
|
|
func (k *kube) Load() ([]*config.KeyValue, error) { |
|
if k.opts.Namespace == "" { |
|
return nil, errors.New("options namespace not full") |
|
} |
|
if err := k.init(); err != nil { |
|
return nil, err |
|
} |
|
return k.load() |
|
} |
|
|
|
func (k *kube) Watch() (config.Watcher, error) { |
|
return newWatcher(k) |
|
}
|
|
|