ConfigMap管理 原创
1、功能
2、类型转换
2.1、实现类型转换
在 internal/pkg/k8s/configmap/common.go
文件中新增 ConfigMapCell
,实现和 corev1.ConfigMapCell
进行类型转换,如下:
package configmap
import (
corev1 "k8s.io/api/core/v1"
"time"
"github.com/joker-bai/hawkeye/internal/pkg/k8s/dataselect"
)
type ConfigMapCell corev1.ConfigMap
func (p ConfigMapCell) GetCreation() time.Time {
return p.CreationTimestamp.Time
}
func (p ConfigMapCell) GetName() string {
return p.Name
}
// toCells batchv1.ConfigMap 类型 转换成 DataCell 类型
// @description: ConfigMap类型转换成DataCell
func toCells(sts []corev1.ConfigMap) []dataselect.DataCell {
cells := make([]dataselect.DataCell, len(sts))
for i := range sts {
cells[i] = ConfigMapCell(sts[i])
}
return cells
}
// fromCells DataCell 类型转换成 batchv1.ConfigMap 类型
// @description: DataCell类型转换成ConfigMap
func fromCells(cells []dataselect.DataCell) []corev1.ConfigMap {
ds := make([]corev1.ConfigMap, len(cells))
for i := range cells {
ds[i] = corev1.ConfigMap(cells[i].(ConfigMapCell))
}
return ds
}
2.2、实现增删改查
(1)创建 internal/pkg/k8s/configmap/create.go 文件,输入以下内容,用于创建 configmap
package configmap
import (
"context"
"github.com/joker-bai/hawkeye/global"
"github.com/joker-bai/hawkeye/internal/app/requests"
"github.com/joker-bai/hawkeye/internal/pkg/k8s/common"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
DescriptionAnnotationKey = "description"
)
func CreateConfigMap(ing *requests.K8sConfigMapCreateRequest) error {
annotations := map[string]string{}
if ing.Description != nil {
annotations[DescriptionAnnotationKey] = *ing.Description
}
labels := common.GetLabelsMap(ing.Labels)
metadata := metav1.ObjectMeta{
Annotations: annotations,
Labels: labels,
Name: ing.Name,
}
serv := &corev1.ConfigMap{
ObjectMeta: metadata,
Data: map[string]string{},
}
for _, config := range ing.Content {
serv.Data[config.Name] = config.Value
}
if _, err := global.K8S.CoreV1().ConfigMaps(ing.Namespace).Create(context.TODO(), serv, metav1.CreateOptions{}); err != nil {
return err
}
return nil
}
(2)在 internal/pkg/k8s/configmap/delete.go 中创建以下内容,用户删除 configmap
package configmap
import (
"context"
"github.com/joker-bai/hawkeye/global"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func DeleteConfigMap(name, namespace string) error {
return global.K8S.CoreV1().ConfigMaps(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
}
(3)在 internal/pkg/k8s/configmap/list.go 中创建以下内容,用于列出 configmap 列表
package configmap
import (
"context"
"github.com/joker-bai/hawkeye/global"
"github.com/joker-bai/hawkeye/internal/pkg/k8s/dataselect"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func ListConfigMap(name, namespace string, page, limit int) ([]corev1.ConfigMap, error) {
global.Log.Info("获取ingress的列表")
list, err := global.K8S.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}
// 做排序
selector := dataselect.DataSelector{
GenericDataList: toCells(list.Items),
DataSelectQuery: &dataselect.DataSelectQuery{
Filter: &dataselect.FilterQuery{
Name: name,
},
Paginate: &dataselect.PaginateQuery{
Limit: limit,
Page: page,
},
},
}
filted := selector.Filter()
data := filted.Sort().Paginate()
return fromCells(data.GenericDataList), nil
}
(4)在 internal/pkg/k8s/configmap/update.go 中创建以下内容,用于更新 configmap
package configmap
import (
"context"
"encoding/json"
"github.com/joker-bai/hawkeye/global"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func UpdateConfigMap(namespace, content string) error {
var sts corev1.ConfigMap
if err := json.Unmarshal([]byte(content), &sts); err != nil {
return err
}
if _, err := global.K8S.CoreV1().ConfigMaps(namespace).Update(context.TODO(), &sts, metav1.UpdateOptions{}); err != nil {
return err
}
return nil
}
(5)在 internal/pkg/k8s/configmap/detail.go 中创建以下内容,用于获取 configmap 详情
package configmap
import (
"context"
"github.com/joker-bai/hawkeye/global"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func GetConfigMapDetail(name, namespace string) (*corev1.ConfigMap, error) {
sts, err := global.K8S.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return sts, nil
}
3、实现 services 方法
3.1、请求参数校验
在 internal/app/requests
目录中新建 k8s_configmap.go
文件,写入以下内容以完成请求参数校验:
package requests
import (
"github.com/gin-gonic/gin"
"github.com/joker-bai/hawkeye/pkg/app"
"github.com/thedevsaddam/govalidator"
)
type K8sConfigMapCreateRequest struct {
Name string `json:"name" form:"name" valid:"name"` // ConfigMap的名字
Namespace string `json:"namespace" form:"namespace" valid:"namespace"` // 名称空间
Description *string `json:"description" form:"description" valid:"description"` // 描述
Labels []Label `json:"labels" form:"labels" valid:"labels"` // 关联标签
Content []DataInfo `json:"content" valid:"content"` // 数据内容
}
type DataInfo struct {
Name string `json:"name" valid:"name"` // 名称
Value string `json:"value" valid:"value"` // 值
}
func ValidK8sConfigMapCreateRequest(data interface{}, ctx *gin.Context) map[string][]string {
rules := govalidator.MapData{
"name": []string{"required"},
"namespace": []string{"required"},
"content": []string{"required"},
}
messages := govalidator.MapData{
"namespace": []string{
"required: namespace不能为空",
},
"name": []string{
"required: name不能为空",
},
"content": []string{
"required: content不能为空",
},
}
return app.ValidateOptions(data, rules, messages)
}
type K8sConfigMapUpdateRequest struct {
Namespace string `json:"namespace" form:"namespace" valid:"namespace"`
Content string `json:"content" form:"content" valid:"content"`
}
func ValidK8sConfigMapUpdateRequest(data interface{}, ctx *gin.Context) map[string][]string {
rules := govalidator.MapData{
"namespace": []string{"required"},
"content": []string{"required"},
}
messages := govalidator.MapData{
"namespace": []string{
"required: namespace 不能为空",
},
"content": []string{
"required: content 不能为空",
},
}
// 校验入参
return app.ValidateOptions(data, rules, messages)
}
type K8sConfigMapListRequest struct {
K8sCommonRequest
Page int `json:"page" form:"page" valid:"page"` // 页数
Limit int `json:"limit" form:"limit" valid:"limit"` // 每页条数
}
func ValidK8sConfigMapListRequest(data interface{}, ctx *gin.Context) map[string][]string {
rules := govalidator.MapData{
"namespace": []string{"required"},
"page": []string{"required"},
"limit": []string{"required"},
}
messages := govalidator.MapData{
"namespace": []string{
"required: namespace不能为空",
},
"page": []string{
"required: page不能为空",
},
"limit": []string{
"required: limit不能为空",
},
}
// 校验入参
return app.ValidateOptions(data, rules, messages)
}
3.2、实现 services 方法
在 internal/app/services/k8s_configmap.go
文件中新增 ConfigMap
操作的 services 方法,如下:
package services
import (
"github.com/joker-bai/hawkeye/internal/app/requests"
"github.com/joker-bai/hawkeye/internal/pkg/k8s/configmap"
corev1 "k8s.io/api/core/v1"
)
// ConfigMap
func (s *Services) K8sConfigMapList(param *requests.K8sConfigMapListRequest) ([]corev1.ConfigMap, error) {
return configmap.ListConfigMap(param.Name, param.Namespace, param.Page, param.Limit)
}
func (s *Services) K8sConfigMapDelete(param *requests.K8sCommonRequest) error {
return configmap.DeleteConfigMap(param.Name, param.Namespace)
}
func (s *Services) K8sConfigMapUpdate(param *requests.K8sConfigMapUpdateRequest) error {
return configmap.UpdateConfigMap(param.Namespace, param.Content)
}
func (s *Services) K8sConfigMapCreate(param *requests.K8sConfigMapCreateRequest) error {
return configmap.CreateConfigMap(param)
}
func (s *Services) K8sConfigMapDetail(param *requests.K8sCommonRequest) (*corev1.ConfigMap, error) {
return configmap.GetConfigMapDetail(param.Name, param.Namespace)
}
4、新增 controllers 方法
在 internal/app/controllers/api/v1/k8s 目录中新增 configmap.go 文件,实现如下方法:
package k8s
import (
"github.com/gin-gonic/gin"
"github.com/joker-bai/hawkeye/global"
"github.com/joker-bai/hawkeye/internal/app/requests"
"github.com/joker-bai/hawkeye/internal/app/services"
"github.com/joker-bai/hawkeye/pkg/app"
"github.com/joker-bai/hawkeye/pkg/errorcode"
"go.uber.org/zap"
)
type ConfigMapController struct{}
// List godoc
// @Summary 列出K8s ConfigMap
// @Description 列出K8s ConfigMap
// @Tags K8s ConfigMap管理
// @Produce json
// @Param name query string false "ConfigMap名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Param page query int true "页码"
// @Param limit query int true "每页数量"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/configmap/list [get]
func (k *ConfigMapController) List(ctx *gin.Context) {
param := requests.K8sConfigMapListRequest{}
response := app.NewResponse(ctx)
if ok := app.Validate(ctx, ¶m, requests.ValidK8sConfigMapListRequest); !ok {
return
}
svc := services.New(ctx)
configmaps, err := svc.K8sConfigMapList(¶m)
if err != nil {
global.Log.Error("获取ConfigMap列表失败", zap.String("error", err.Error()))
response.ToErrorResponse(errorcode.ErrorK8sConfigMapListFail)
return
}
response.ToResponseList(configmaps, len(configmaps))
}
// Update godoc
// @Summary 更新ConfigMap
// @Description 更新ConfigMap
// @Tags K8s ConfigMap管理
// @Produce json
// @Param body body requests.K8sConfigMapUpdateRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/configmap/update [post]
func (k *ConfigMapController) Update(ctx *gin.Context) {
param := requests.K8sConfigMapUpdateRequest{}
response := app.NewResponse(ctx)
if ok := app.Validate(ctx, ¶m, requests.ValidK8sConfigMapUpdateRequest); !ok {
return
}
svc := services.New(ctx)
err := svc.K8sConfigMapUpdate(¶m)
if err != nil {
global.Log.Error("更新ConfigMap失败", zap.String("error", err.Error()))
response.ToErrorResponse(errorcode.ErrorK8sConfigMapUpdateFail)
return
}
response.ToResponse(gin.H{
"msg": "ConfigMap更新成功",
})
}
// Delete godoc
// @Summary 删除ConfigMap
// @Description 删除ConfigMap
// @Tags K8s ConfigMap管理
// @Produce json
// @Param body body requests.K8sCommonRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/configmap/delete [post]
func (k *ConfigMapController) Delete(ctx *gin.Context) {
param := requests.K8sCommonRequest{}
response := app.NewResponse(ctx)
if ok := app.Validate(ctx, ¶m, requests.ValidK8sCommonRequest); !ok {
return
}
svc := services.New(ctx)
err := svc.K8sConfigMapDelete(¶m)
if err != nil {
global.Log.Error("删除ConfigMaps失败", zap.String("error", err.Error()))
response.ToErrorResponse(errorcode.ErrorK8sConfigMapDeleteFail)
return
}
response.ToResponse(gin.H{
"msg": "ConfigMap删除成功",
})
}
// Create godoc
// @Summary 创建ConfigMap
// @Description 创建ConfigMap
// @Tags K8s ConfigMap管理
// @Produce json
// @Param body body requests.K8sConfigMapCreateRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/configmap/create [post]
func (k *ConfigMapController) Create(ctx *gin.Context) {
param := requests.K8sConfigMapCreateRequest{}
response := app.NewResponse(ctx)
if ok := app.Validate(ctx, ¶m, requests.ValidK8sConfigMapCreateRequest); !ok {
return
}
svc := services.New(ctx)
err := svc.K8sConfigMapCreate(¶m)
if err != nil {
global.Log.Error("创建ConfigMap失败", zap.String("error", err.Error()))
response.ToErrorResponse(errorcode.ErrorK8sConfigMapCreateFail)
return
}
response.ToResponse(gin.H{
"msg": "ConfigMap创建成功",
})
}
// Detail godoc
// @Summary 获取ConfigMap的详情
// @Description 获取ConfigMap的详情
// @Tags K8s ConfigMap管理
// @Produce json
// @Param name query string false "ConfigMap名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/configmap/detail [get]
func (k *ConfigMapController) Detail(ctx *gin.Context) {
param := requests.K8sCommonRequest{}
response := app.NewResponse(ctx)
if ok := app.Validate(ctx, ¶m, requests.ValidK8sCommonRequest); !ok {
return
}
svc := services.New(ctx)
configmap, err := svc.K8sConfigMapDetail(¶m)
if err != nil {
global.Log.Error("获取获取ConfigMap的详情失败", zap.String("error", err.Error()))
response.ToErrorResponse(errorcode.ErrorK8sConfigMapDetailFail)
return
}
response.ToResponse(gin.H{
"data": configmap,
"msg": "获取ConfigMap的详情成功",
})
}
再到 pkg/errorcode/k8s.go
文件中新增如下错误代码:
package errorcode
var (
......
// K8s ConfigMap 错误码
ErrorK8sConfigMapUpdateFail = NewError(500101, "更新K8s ConfigMap 失败")
ErrorK8sConfigMapDeleteFail = NewError(500102, "删除K8s ConfigMap 失败")
ErrorK8sConfigMapListFail = NewError(500103, "获取K8s ConfigMap 列表失败")
ErrorK8sConfigMapDetailFail = NewError(500104, "获取K8s ConfigMap 详情失败")
ErrorK8sConfigMapCreateFail = NewError(500105, "创建K8s ConfigMap 失败")
)
5、新增路由
在 internal/app/routers/k8s.go
文件中新增 ConfigMap
操作的路由,如下:
package routers
import (
"github.com/gin-gonic/gin"
v1 "github.com/joker-bai/kubemana/internal/app/controllers/api/v1"
)
type K8sRouter struct{}
func (r *K8sRouter) Inject(router *gin.RouterGroup) {
k8s := router.Group("/k8s")
{
......
// ConfigMap 管理
cmc := new(k8s.ConfigMapController)
ks.GET("/configmap/list", cmc.List)
ks.POST("/configmap/create", cmc.Create)
ks.POST("/configmap/update", cmc.Update)
ks.POST("/configmap/delete", cmc.Delete)
ks.GET("/configmap/detail", cmc.Detail)
}
}
6、测试一下
PS:测试之前都需要先初始化集群,在 4.3.1 Pod 章节有介绍。
这里简单测试列出 ConfigMap 接口,如下:
其他接口自行下去测试。
7、代码版本
本节开发完成后,记得生成 swag 和标记代码版本,如下:
$ swag init
$ git add .
$ git commit -m "新增k8s集群configmap操作"