-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
753 additions
and
210 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
|
||
api "github.com/chaitin/libveinmind/go" | ||
"github.com/chaitin/libveinmind/go/plugin" | ||
) | ||
|
||
// ScanClusters scans cluster list. | ||
func ScanClusters( | ||
ctx context.Context, rang plugin.ExecRange, | ||
cluster []api.Cluster, opts ...plugin.ExecOption, | ||
) error { | ||
iter, err := plugin.IterateTyped(rang, "cluster") | ||
if err != nil { | ||
return err | ||
} | ||
return Scan(ctx, iter, cluster, | ||
plugin.WithExecOptions(opts...)) | ||
} | ||
|
||
// ClusterHandler is the handler for specified cluster. | ||
type ClusterHandler func(*Command, api.Cluster) error | ||
|
||
// MapClusterCommand issues defaultIndex.MapClusterCommand. | ||
func MapClusterCommand( | ||
c *Command, f ClusterHandler, | ||
) *Command { | ||
return defaultIndex.MapClusterCommand(c, f) | ||
} | ||
|
||
// MapClusterCommand attempts to create a cluster command. | ||
// | ||
// The command will attempt to initialize the cluster object | ||
// from specified mode with flags, and then invoke the function | ||
// specified by caller. | ||
func (idx *Index) MapClusterCommand( | ||
c *Command, f ClusterHandler, | ||
) *Command { | ||
return idx.MapModeCommand(c, "cluster", struct{}{}, func( | ||
c *Command, _ []string, root interface{}, | ||
) error { | ||
r, ok := root.(api.Cluster) | ||
if !ok { | ||
return IncompatibleMode() | ||
} | ||
return f(c, r) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/spf13/pflag" | ||
|
||
"github.com/chaitin/libveinmind/go/kubernetes" | ||
"github.com/chaitin/libveinmind/go/pkg/pflagext" | ||
"github.com/chaitin/libveinmind/go/plugin" | ||
) | ||
|
||
type kubernetesRoot struct { | ||
k *kubernetes.Kubernetes | ||
} | ||
|
||
func (r kubernetesRoot) ID() interface{} { | ||
return r.k | ||
} | ||
|
||
func (r kubernetesRoot) Mode() string { | ||
return "kubernetes" | ||
} | ||
|
||
func (r kubernetesRoot) Options() plugin.ExecOption { | ||
return plugin.WithExecOptions(plugin.WithPrependArgs( | ||
"--kube-config", r.k.ConfigPath()), | ||
plugin.WithPrependArgs( | ||
"--namespace", r.k.CurrentNamespace())) | ||
} | ||
|
||
var kubernetesFlags []kubernetes.NewOption | ||
|
||
type kubernetesMode struct { | ||
} | ||
|
||
func (kubernetesMode) Name() string { | ||
return "kubernetes" | ||
} | ||
|
||
func (kubernetesMode) AddFlags(fset *pflag.FlagSet) { | ||
pflagext.StringVarF(fset, func(path string) error { | ||
kubernetesFlags = append(kubernetesFlags, | ||
kubernetes.WithKubeConfig(path)) | ||
return nil | ||
}, "kube-config", | ||
`flag "--kube-config" specified kube config`) | ||
pflagext.StringVarF(fset, func(namespace string) error { | ||
kubernetesFlags = append(kubernetesFlags, | ||
kubernetes.WithNamespace(namespace)) | ||
return nil | ||
}, "namespace", | ||
`flag "--namespace" specified namespace`) | ||
} | ||
|
||
func (kubernetesMode) Invoke(c *Command, args []string, m ModeHandler) error { | ||
k, err := kubernetes.New(kubernetesFlags...) | ||
if err != nil { | ||
return err | ||
} | ||
defer func() { _ = k.Close() }() | ||
return m(c, args, k) | ||
} | ||
|
||
func init() { | ||
RegisterPartition(func(k *kubernetes.Kubernetes) Root { | ||
return kubernetesRoot{k: k} | ||
}) | ||
RegisterMode(&kubernetesMode{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package kubernetes | ||
|
||
type NamespaceKind string | ||
type ClusterKind string | ||
|
||
const ( | ||
Deployments NamespaceKind = "deployments" | ||
ReplicaSets NamespaceKind = "replicasets" | ||
ReplicationControllers NamespaceKind = "replicationcontrollers" | ||
StatefulSets NamespaceKind = "statefulsets" | ||
DaemonSets NamespaceKind = "daemonsets" | ||
CronJobs NamespaceKind = "cronjobs" | ||
Services NamespaceKind = "services" | ||
Jobs NamespaceKind = "jobs" | ||
Pods NamespaceKind = "pods" | ||
ConfigMaps NamespaceKind = "configmaps" | ||
Roles NamespaceKind = "roles" | ||
RoleBindings NamespaceKind = "rolebindings" | ||
NetworkPolicys NamespaceKind = "networkpolicies" | ||
Ingresss NamespaceKind = "ingresses" | ||
ResourceQuotas NamespaceKind = "resourcequotas" | ||
LimitRanges NamespaceKind = "limitranges" | ||
) | ||
|
||
const ( | ||
ComponentStatus ClusterKind = "componentstatuses" | ||
Nodes ClusterKind = "nodes" | ||
Namespaces ClusterKind = "namespaces" | ||
PersistentVolumes ClusterKind = "persistentvolumes" | ||
ClusterRoles ClusterKind = "clusterroles" | ||
ClusterRoleBindings ClusterKind = "clusterrolebindings" | ||
PodSecurityPolicies ClusterKind = "podsecuritypolicies" | ||
) | ||
|
||
func (k NamespaceKind) String() string { | ||
return string(k) | ||
} | ||
|
||
func (k ClusterKind) String() string { | ||
return string(k) | ||
} | ||
|
||
func GetNamespaceKinds() []NamespaceKind { | ||
return []NamespaceKind{ | ||
Deployments, | ||
ReplicaSets, | ||
ReplicationControllers, | ||
StatefulSets, | ||
DaemonSets, | ||
CronJobs, | ||
Services, | ||
Jobs, | ||
Pods, | ||
ConfigMaps, | ||
Roles, | ||
RoleBindings, | ||
NetworkPolicys, | ||
Ingresss, | ||
ResourceQuotas, | ||
LimitRanges, | ||
} | ||
} | ||
|
||
func GetClusterKinds() []ClusterKind { | ||
return []ClusterKind{ | ||
ComponentStatus, | ||
Nodes, | ||
Namespaces, | ||
PersistentVolumes, | ||
ClusterRoles, | ||
ClusterRoleBindings, | ||
PodSecurityPolicies, | ||
} | ||
} | ||
|
||
func IsNamespaceKind(kind string) bool { | ||
for _, namespaceKind := range GetNamespaceKinds() { | ||
if namespaceKind.String() == kind { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
func IsClusterKind(kind string) bool { | ||
for _, clusterKind := range GetClusterKinds() { | ||
if clusterKind.String() == kind { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package kubernetes | ||
|
||
import ( | ||
"context" | ||
"os" | ||
|
||
"github.com/pkg/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
"k8s.io/client-go/dynamic" | ||
|
||
api "github.com/chaitin/libveinmind/go" | ||
) | ||
|
||
type Kubernetes struct { | ||
// kubernetes cluster namespace | ||
namespace string | ||
|
||
// kube kubeConfig path for cluster | ||
kubeConfig string | ||
|
||
// dynamicClient reference dynamic.Interface | ||
// return data use map[string]interface{} format | ||
dynamicClient dynamic.Interface | ||
|
||
// restMapper reference mete.RESTMapper | ||
// used to fetch schema.GroupVersionResource from kind | ||
restMapper meta.RESTMapper | ||
} | ||
|
||
type NewOption func(kubernetes *Kubernetes) error | ||
|
||
func WithNamespace(namespace string) NewOption { | ||
return func(kubernetes *Kubernetes) error { | ||
kubernetes.namespace = namespace | ||
return nil | ||
} | ||
} | ||
|
||
func WithKubeConfig(path string) NewOption { | ||
return func(kubernetes *Kubernetes) error { | ||
kubernetes.kubeConfig = path | ||
return nil | ||
} | ||
} | ||
|
||
func New(options ...NewOption) (*Kubernetes, error) { | ||
k := new(Kubernetes) | ||
|
||
for _, opt := range options { | ||
err := opt(k) | ||
if err != nil { | ||
continue | ||
} | ||
} | ||
|
||
if k.kubeConfig == "" { | ||
if os.Getenv("KUBECONFIG") == "" { | ||
return nil, errors.New("kubernetes: can't find kube config path") | ||
} else { | ||
k.kubeConfig = os.Getenv("KUBECONFIG") | ||
} | ||
} | ||
|
||
if k.namespace == "" { | ||
k.namespace = "default" | ||
} | ||
|
||
// init dynamic client config | ||
config := genericclioptions.NewConfigFlags(true) | ||
*config.KubeConfig = k.kubeConfig | ||
configLoader := config.ToRawKubeConfigLoader() | ||
restConfig, err := configLoader.ClientConfig() | ||
if err != nil { | ||
return nil, errors.Wrap(err, "kubernetes: can't get rest config") | ||
} | ||
|
||
// init dynamic client | ||
dynamicClient, err := dynamic.NewForConfig(restConfig) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "kubernetes: can't init dynamic client") | ||
} | ||
k.dynamicClient = dynamicClient | ||
|
||
// init rest mapper | ||
mapper, err := config.ToRESTMapper() | ||
if err != nil { | ||
return nil, errors.Wrap(err, "kubernetes: can't init rest mapper") | ||
} | ||
k.restMapper = mapper | ||
|
||
return k, nil | ||
} | ||
|
||
func (k *Kubernetes) ListNamespaces() ([]string, error) { | ||
namespaceResource, err := k.Resource(Namespaces.String()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return namespaceResource.List(context.Background()) | ||
} | ||
|
||
func (k *Kubernetes) CurrentNamespace() string { | ||
return k.namespace | ||
} | ||
|
||
func (k *Kubernetes) ConfigPath() string { | ||
return k.kubeConfig | ||
} | ||
|
||
func (k *Kubernetes) Namespace(namespace string) api.Cluster { | ||
k.namespace = namespace | ||
return k | ||
} | ||
|
||
func (k *Kubernetes) Resource(kind string) (api.ClusterResource, error) { | ||
gvr, err := k.restMapper.ResourceFor(schema.GroupVersionResource{Resource: kind}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// cluster resource can't use namespace (namespaced is false) | ||
if IsClusterKind(kind) { | ||
return Resource{kind, k.dynamicClient.Resource(gvr)}, nil | ||
} else if IsNamespaceKind(kind) { | ||
return Resource{kind, k.dynamicClient.Resource(gvr).Namespace(k.namespace)}, nil | ||
} else { | ||
return nil, errors.New("kubernetes: not support resource kind for cluster") | ||
} | ||
} | ||
|
||
func (k *Kubernetes) Close() error { | ||
return nil | ||
} |
Oops, something went wrong.