🎉
This commit is contained in:
126
k8s/client.go
Normal file
126
k8s/client.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
appv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
kindv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
kubernetes.Interface
|
||||
}
|
||||
|
||||
// Client
|
||||
// @description: 获取客户端
|
||||
// @receiver c
|
||||
// @return *client
|
||||
// @return error
|
||||
func (c *config) Client() (*client, error) {
|
||||
|
||||
kubeClient, err := kubernetes.NewForConfig(c.resetConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &client{kubeClient}, nil
|
||||
|
||||
}
|
||||
|
||||
// Do
|
||||
// @description: 执行
|
||||
// @receiver c
|
||||
// @param namespace
|
||||
// @param kind
|
||||
// @param resourceName
|
||||
// @param actionMethod
|
||||
// @param repo
|
||||
// @return err
|
||||
func (c client) Do(namespace, kind, resourceName, actionMethod, repo string) (err error) {
|
||||
|
||||
fmt.Println("命名空间: ", namespace)
|
||||
fmt.Println("资源类型: ", kind)
|
||||
fmt.Println("资源名称: ", resourceName)
|
||||
fmt.Println("操作类型: ", actionMethod)
|
||||
fmt.Println("镜像地址: ", repo)
|
||||
|
||||
var kindType any // 应用类型
|
||||
var resource any // 资源详情
|
||||
|
||||
switch kind {
|
||||
case "Deployment":
|
||||
|
||||
kindType = c.AppsV1().Deployments(namespace)
|
||||
// 获取一下资源
|
||||
resource, err = kindType.(kindv1.DeploymentInterface).Get(context.Background(), resourceName, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("get deployment error: %v", err.Error())
|
||||
}
|
||||
|
||||
switch actionMethod {
|
||||
case "create":
|
||||
case "update": // 更新,目前仅支持更新镜像和tag
|
||||
|
||||
if err != nil && resource == nil {
|
||||
return fmt.Errorf("get deployment error: %v", err.Error())
|
||||
}
|
||||
|
||||
if repo == "" {
|
||||
return fmt.Errorf("repo not empty")
|
||||
}
|
||||
|
||||
// 解析规则,判断是只单独变更tag还是镜像整个替换
|
||||
if !strings.Contains(repo, ":") {
|
||||
resource.(*appv1.Deployment).Spec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", strings.Split(resource.(*appv1.Deployment).Spec.Template.Spec.Containers[0].Image, ":")[0], repo)
|
||||
} else {
|
||||
resource.(*appv1.Deployment).Spec.Template.Spec.Containers[0].Image = repo
|
||||
}
|
||||
|
||||
_, err = kindType.(kindv1.DeploymentInterface).Update(context.Background(), resource.(*appv1.Deployment), metav1.UpdateOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("update deployment error: %v", err.Error())
|
||||
}
|
||||
|
||||
case "delete": // 删除应用
|
||||
if err != nil && resource == nil {
|
||||
return fmt.Errorf("get deployment error: %v", err.Error())
|
||||
}
|
||||
|
||||
err = kindType.(kindv1.DeploymentInterface).Delete(context.Background(), resourceName, metav1.DeleteOptions{})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "restart": // 重启应用
|
||||
if err != nil && resource == nil {
|
||||
return fmt.Errorf("get deployment error: %v", err.Error())
|
||||
}
|
||||
|
||||
rJ, _ := json.Marshal(resource)
|
||||
|
||||
fmt.Println(string(rJ))
|
||||
|
||||
resource.(*appv1.Deployment).Spec.Template.ObjectMeta.Annotations["kubectl.kubernetes.io/restartedAt"] = time.Now().Local().String()
|
||||
_, err = kindType.(kindv1.DeploymentInterface).Update(context.Background(), resource.(*appv1.Deployment), metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
kindType = c.AppsV1().Deployments(namespace)
|
||||
default:
|
||||
return errors.New("not support")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
156
k8s/config.go
Normal file
156
k8s/config.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Host string `json:"host"` // K8S地址
|
||||
AuthType AuthType `json:"authType"` // 认证方式 0:config 1:token
|
||||
Config string `json:"config"` // 认证配置文件
|
||||
Token string `json:"token"` // 认证Token
|
||||
IsSkipTls bool `json:"isSkipTls"` // 是否跳过TLS认证
|
||||
CaCrt string `json:"caCrt"` // CA证书
|
||||
ClusterName string `json:"clusterName"` // 集群名称
|
||||
|
||||
resetConf *rest.Config
|
||||
}
|
||||
|
||||
type option func(c *config)
|
||||
|
||||
func WithHost(host string) option {
|
||||
return func(c *config) {
|
||||
c.Host = host
|
||||
}
|
||||
}
|
||||
|
||||
func WithAuthType(authType string) option {
|
||||
return func(c *config) {
|
||||
switch strings.ToUpper(authType) {
|
||||
case "CONFIG":
|
||||
c.AuthType = AuthConfig
|
||||
case "TOKEN":
|
||||
c.AuthType = AuthToken
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithConfig(conf string) option {
|
||||
return func(c *config) {
|
||||
c.Config = conf
|
||||
}
|
||||
}
|
||||
|
||||
func WithToken(token string) option {
|
||||
return func(c *config) {
|
||||
c.Token = token
|
||||
}
|
||||
}
|
||||
|
||||
func WithIsSkipTls(isSkipTls bool) option {
|
||||
return func(c *config) {
|
||||
c.IsSkipTls = isSkipTls
|
||||
}
|
||||
}
|
||||
|
||||
func WithCaCrt(caCrt string) option {
|
||||
return func(c *config) {
|
||||
c.CaCrt = caCrt
|
||||
}
|
||||
}
|
||||
|
||||
func WithCluster(cluster string) option {
|
||||
return func(c *config) {
|
||||
c.ClusterName = cluster
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfig(opts ...option) (*config, error) {
|
||||
c := &config{}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
|
||||
if err := c.valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var restConfig *rest.Config
|
||||
var err error
|
||||
|
||||
switch c.AuthType {
|
||||
case AuthToken:
|
||||
|
||||
restConfig, err = clientcmd.BuildConfigFromKubeconfigGetter(c.Host, func() (*api.Config, error) {
|
||||
apiConf := &api.Config{
|
||||
Clusters: map[string]*api.Cluster{
|
||||
c.ClusterName: {
|
||||
Server: c.Host,
|
||||
InsecureSkipTLSVerify: c.IsSkipTls,
|
||||
CertificateAuthorityData: []byte(c.CaCrt),
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*api.AuthInfo{
|
||||
c.ClusterName: {
|
||||
Token: c.Token,
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*api.Context{
|
||||
c.ClusterName: {
|
||||
Cluster: c.ClusterName,
|
||||
AuthInfo: c.ClusterName,
|
||||
},
|
||||
},
|
||||
CurrentContext: c.ClusterName,
|
||||
}
|
||||
|
||||
// 如果跳过TLS认证,则清空CA证书
|
||||
if c.IsSkipTls {
|
||||
apiConf.Clusters[c.ClusterName].InsecureSkipTLSVerify = c.IsSkipTls
|
||||
apiConf.Clusters[c.ClusterName].CertificateAuthorityData = nil
|
||||
}
|
||||
|
||||
return apiConf, nil
|
||||
})
|
||||
|
||||
case AuthConfig:
|
||||
restConfig, err = clientcmd.BuildConfigFromFlags(c.Host, c.GetConfigPath())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.resetConf = restConfig
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *config) valid() error {
|
||||
if !strings.HasPrefix(c.Host, "https://") && !strings.HasPrefix(c.Host, "http://") {
|
||||
c.Host = fmt.Sprintf("https://%s", c.Host)
|
||||
}
|
||||
|
||||
if c.Token == "" && c.Config == "" {
|
||||
return fmt.Errorf("auth token or auth config not empty")
|
||||
}
|
||||
|
||||
if c.ClusterName == "" {
|
||||
c.ClusterName = "default"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) GetConfigPath() string {
|
||||
if err := os.WriteFile("./kubernetes", []byte(c.Config), 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return "./kubernetes"
|
||||
}
|
8
k8s/const.go
Normal file
8
k8s/const.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package k8s
|
||||
|
||||
type AuthType int
|
||||
|
||||
const (
|
||||
AuthConfig = iota
|
||||
AuthToken
|
||||
)
|
Reference in New Issue
Block a user