mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-11-30 02:38:17 +08:00
Merge branch 'feature-k8s' of https://github.com/goodrain/rainbond into merge-feature-k8s-main
This commit is contained in:
commit
a37cee6456
@ -30,6 +30,17 @@ type ClusterInterface interface {
|
||||
MavenSettingUpdate(w http.ResponseWriter, r *http.Request)
|
||||
MavenSettingDelete(w http.ResponseWriter, r *http.Request)
|
||||
MavenSettingDetail(w http.ResponseWriter, r *http.Request)
|
||||
GetNamespace(w http.ResponseWriter, r *http.Request)
|
||||
GetNamespaceResource(w http.ResponseWriter, r *http.Request)
|
||||
ConvertResource(w http.ResponseWriter, r *http.Request)
|
||||
ResourceImport(w http.ResponseWriter, r *http.Request)
|
||||
AddResource(w http.ResponseWriter, r *http.Request)
|
||||
DeleteResource(w http.ResponseWriter, r *http.Request)
|
||||
UpdateResource(w http.ResponseWriter, r *http.Request)
|
||||
SyncResource(w http.ResponseWriter, r *http.Request)
|
||||
YamlResourceName(w http.ResponseWriter, r *http.Request)
|
||||
YamlResourceDetailed(w http.ResponseWriter, r *http.Request)
|
||||
YamlResourceImport(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
//TenantInterface interface
|
||||
@ -88,6 +99,8 @@ type ServiceInterface interface {
|
||||
AddServiceMonitors(w http.ResponseWriter, r *http.Request)
|
||||
DeleteServiceMonitors(w http.ResponseWriter, r *http.Request)
|
||||
UpdateServiceMonitors(w http.ResponseWriter, r *http.Request)
|
||||
UploadPackage(w http.ResponseWriter, r *http.Request)
|
||||
K8sAttributes(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
//TenantInterfaceWithV1 funcs for both v2 and v1
|
||||
@ -153,6 +166,7 @@ type AppInterface interface {
|
||||
NewUpload(w http.ResponseWriter, r *http.Request)
|
||||
ImportID(w http.ResponseWriter, r *http.Request)
|
||||
ImportApp(w http.ResponseWriter, r *http.Request)
|
||||
UploadID(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// ApplicationInterface tenant application interface
|
||||
@ -172,7 +186,6 @@ type ApplicationInterface interface {
|
||||
Install(w http.ResponseWriter, r *http.Request)
|
||||
ListServices(w http.ResponseWriter, r *http.Request)
|
||||
ListHelmAppReleases(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
DeleteConfigGroup(w http.ResponseWriter, r *http.Request)
|
||||
ListConfigGroups(w http.ResponseWriter, r *http.Request)
|
||||
SyncComponents(w http.ResponseWriter, r *http.Request)
|
||||
|
@ -94,6 +94,17 @@ func (v2 *V2) clusterRouter() chi.Router {
|
||||
r.Get("/builder/mavensetting/{name}", controller.GetManager().MavenSettingDetail)
|
||||
r.Put("/builder/mavensetting/{name}", controller.GetManager().MavenSettingUpdate)
|
||||
r.Delete("/builder/mavensetting/{name}", controller.GetManager().MavenSettingDelete)
|
||||
r.Get("/namespace", controller.GetManager().GetNamespace)
|
||||
r.Get("/resource", controller.GetManager().GetNamespaceResource)
|
||||
r.Get("/convert-resource", controller.GetManager().ConvertResource)
|
||||
r.Post("/convert-resource", controller.GetManager().ResourceImport)
|
||||
r.Post("/k8s-resource", controller.GetManager().AddResource)
|
||||
r.Delete("/k8s-resource", controller.GetManager().DeleteResource)
|
||||
r.Put("/k8s-resource", controller.GetManager().UpdateResource)
|
||||
r.Post("/sync-k8s-resources", controller.GetManager().SyncResource)
|
||||
r.Get("/yaml_resource_name", controller.GetManager().YamlResourceName)
|
||||
r.Get("/yaml_resource_detailed", controller.GetManager().YamlResourceDetailed)
|
||||
r.Post("/yaml_resource_import", controller.GetManager().YamlResourceImport)
|
||||
return r
|
||||
}
|
||||
|
||||
@ -273,6 +284,10 @@ func (v2 *V2) serviceRouter() chi.Router {
|
||||
r.Put("/label", middleware.WrapEL(controller.GetManager().Label, dbmodel.TargetTypeService, "update-service-label", dbmodel.SYNEVENTTYPE))
|
||||
r.Delete("/label", middleware.WrapEL(controller.GetManager().Label, dbmodel.TargetTypeService, "delete-service-label", dbmodel.SYNEVENTTYPE))
|
||||
|
||||
// Component K8s properties are modified
|
||||
r.Post("/k8s-attributes", middleware.WrapEL(controller.GetManager().K8sAttributes, dbmodel.TargetTypeService, "create-component-k8s-attributes", dbmodel.SYNEVENTTYPE))
|
||||
r.Put("/k8s-attributes", middleware.WrapEL(controller.GetManager().K8sAttributes, dbmodel.TargetTypeService, "update-component-k8s-attributes", dbmodel.SYNEVENTTYPE))
|
||||
r.Delete("/k8s-attributes", middleware.WrapEL(controller.GetManager().K8sAttributes, dbmodel.TargetTypeService, "delete-component-k8s-attributes", dbmodel.SYNEVENTTYPE))
|
||||
//插件
|
||||
r.Mount("/plugin", v2.serviceRelatePluginRouter())
|
||||
|
||||
@ -383,6 +398,10 @@ func (v2 *V2) appRouter() chi.Router {
|
||||
r.Post("/import", controller.GetManager().ImportApp)
|
||||
r.Get("/import/{eventID}", controller.GetManager().ImportApp)
|
||||
r.Delete("/import/{eventID}", controller.GetManager().ImportApp)
|
||||
|
||||
r.Post("/upload/events/{eventID}", controller.GetManager().UploadID)
|
||||
r.Get("/upload/events/{eventID}", controller.GetManager().UploadID)
|
||||
r.Delete("/upload/events/{eventID}", controller.GetManager().UploadID)
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -52,3 +52,11 @@ func AppRoutes() chi.Router {
|
||||
r.Options("/upload/{eventID}", controller.GetManager().Upload)
|
||||
return r
|
||||
}
|
||||
|
||||
//PackageBuildRoutes 本地文件上传路由
|
||||
func PackageBuildRoutes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
r.Post("/component/events/{eventID}", controller.GetManager().UploadPackage)
|
||||
r.Options("/component/events/{eventID}", controller.GetManager().UploadPackage)
|
||||
return r
|
||||
}
|
||||
|
@ -156,6 +156,75 @@ func (a *AppStruct) ImportID(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
//UploadID -
|
||||
func (a *AppStruct) UploadID(w http.ResponseWriter, r *http.Request) {
|
||||
eventID := strings.TrimSpace(chi.URLParam(r, "eventID"))
|
||||
if eventID == "" {
|
||||
httputil.ReturnError(r, w, 400, "Failed to parse eventID.")
|
||||
return
|
||||
}
|
||||
dirName := fmt.Sprintf("/grdata/package_build/temp/events/%s", eventID)
|
||||
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
err := os.MkdirAll(dirName, 0755)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 502, "Failed to create directory by event id: "+err.Error())
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, map[string]string{"path": dirName})
|
||||
case "GET":
|
||||
_, err := os.Stat(dirName)
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
err := os.MkdirAll(dirName, 0755)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 502, "Failed to create directory by event id: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
packages, err := ioutil.ReadDir(dirName)
|
||||
if err != nil {
|
||||
httputil.ReturnSuccess(r, w, map[string][]string{"packages": {}})
|
||||
return
|
||||
}
|
||||
|
||||
packageArr := make([]string, 0, 10)
|
||||
for _, dir := range packages {
|
||||
if dir.IsDir() {
|
||||
continue
|
||||
}
|
||||
ex := filepath.Ext(dir.Name())
|
||||
if ex != ".jar" && ex != ".war" && ex != ".yaml" && ex != ".yml"{
|
||||
continue
|
||||
}
|
||||
packageArr = append(packageArr, dir.Name())
|
||||
}
|
||||
|
||||
httputil.ReturnSuccess(r, w, map[string][]string{"packages": packageArr})
|
||||
case "DELETE":
|
||||
cmd := exec.Command("rm", "-rf", dirName)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil && err.Error() != "exit status 1" {
|
||||
logrus.Errorf("rm -rf %s failed: %s", dirName, err.Error())
|
||||
httputil.ReturnError(r, w, 501, "Failed to delete directory by id: "+eventID)
|
||||
return
|
||||
}
|
||||
res, err := db.GetManager().AppDao().GetByEventId(eventID)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 404, fmt.Sprintf("Failed to query status of export app by event id %s: %v", eventID, err))
|
||||
return
|
||||
}
|
||||
res.Status = "cleaned"
|
||||
db.GetManager().AppDao().UpdateModel(res)
|
||||
httputil.ReturnSuccess(r, w, "successful")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//NewUpload -
|
||||
func (a *AppStruct) NewUpload(w http.ResponseWriter, r *http.Request) {
|
||||
eventID := strings.TrimSpace(chi.URLParam(r, "eventID"))
|
||||
|
@ -19,6 +19,7 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
@ -101,3 +102,169 @@ func (t *ClusterController) MavenSettingDetail(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, c)
|
||||
}
|
||||
|
||||
//GetNamespace Get the unconnected namespaces under the current cluster
|
||||
func (t *ClusterController) GetNamespace(w http.ResponseWriter, r *http.Request) {
|
||||
content := r.FormValue("content")
|
||||
ns, err := handler.GetClusterHandler().GetNamespace(r.Context(), content)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, ns)
|
||||
}
|
||||
|
||||
//GetNamespaceResource Get all resources in the current namespace
|
||||
func (t *ClusterController) GetNamespaceResource(w http.ResponseWriter, r *http.Request) {
|
||||
content := r.FormValue("content")
|
||||
namespace := r.FormValue("namespace")
|
||||
rs, err := handler.GetClusterHandler().GetNamespaceSource(r.Context(), content, namespace)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, rs)
|
||||
}
|
||||
|
||||
//ConvertResource Get the resources under the current namespace to the rainbond platform
|
||||
func (t *ClusterController) ConvertResource(w http.ResponseWriter, r *http.Request) {
|
||||
content := r.FormValue("content")
|
||||
namespace := r.FormValue("namespace")
|
||||
rs, err := handler.GetClusterHandler().GetNamespaceSource(r.Context(), content, namespace)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
appsServices, err := handler.GetClusterHandler().ConvertResource(r.Context(), namespace, rs)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, appsServices)
|
||||
}
|
||||
|
||||
//ResourceImport Import the converted k8s resources into recognition
|
||||
func (t *ClusterController) ResourceImport(w http.ResponseWriter, r *http.Request) {
|
||||
content := r.FormValue("content")
|
||||
namespace := r.FormValue("namespace")
|
||||
eid := r.FormValue("eid")
|
||||
rs, err := handler.GetClusterHandler().GetNamespaceSource(r.Context(), content, namespace)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
appsServices, err := handler.GetClusterHandler().ConvertResource(r.Context(), namespace, rs)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
rri, err := handler.GetClusterHandler().ResourceImport(namespace, appsServices, eid)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, rri)
|
||||
}
|
||||
|
||||
//AddResource -
|
||||
func (t *ClusterController) AddResource(w http.ResponseWriter, r *http.Request) {
|
||||
var hr model.AddHandleResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &hr, nil); !ok {
|
||||
return
|
||||
}
|
||||
rri, err := handler.GetClusterHandler().AddAppK8SResource(r.Context(), hr.Namespace, hr.AppID, hr.ResourceYaml)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, rri)
|
||||
}
|
||||
|
||||
//UpdateResource -
|
||||
func (t *ClusterController) UpdateResource(w http.ResponseWriter, r *http.Request) {
|
||||
var hr model.HandleResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &hr, nil); !ok {
|
||||
return
|
||||
}
|
||||
rri, err := handler.GetClusterHandler().UpdateAppK8SResource(r.Context(), hr.Namespace, hr.AppID, hr.Name, hr.ResourceYaml, hr.Kind)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, rri)
|
||||
}
|
||||
|
||||
//DeleteResource -
|
||||
func (t *ClusterController) DeleteResource(w http.ResponseWriter, r *http.Request) {
|
||||
var hr model.HandleResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &hr, nil); !ok {
|
||||
return
|
||||
}
|
||||
err := handler.GetClusterHandler().DeleteAppK8SResource(r.Context(), hr.Namespace, hr.AppID, hr.Name, hr.ResourceYaml, hr.Kind)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, nil)
|
||||
}
|
||||
|
||||
// SyncResource -
|
||||
func (t *ClusterController) SyncResource(w http.ResponseWriter, r *http.Request) {
|
||||
var req model.SyncResources
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &req, nil); !ok {
|
||||
return
|
||||
}
|
||||
resources, err := handler.GetClusterHandler().SyncAppK8SResources(r.Context(), &req)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, resources)
|
||||
}
|
||||
|
||||
//YamlResourceName -
|
||||
func (t *ClusterController) YamlResourceName(w http.ResponseWriter, r *http.Request) {
|
||||
var yr model.YamlResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &yr, nil); !ok {
|
||||
return
|
||||
}
|
||||
h, err := handler.GetClusterHandler().AppYamlResourceName(yr)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, h)
|
||||
}
|
||||
|
||||
//YamlResourceDetailed -
|
||||
func (t *ClusterController) YamlResourceDetailed(w http.ResponseWriter, r *http.Request) {
|
||||
var yr model.YamlResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &yr, nil); !ok {
|
||||
return
|
||||
}
|
||||
h, err := handler.GetClusterHandler().AppYamlResourceDetailed(yr, false)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, h)
|
||||
}
|
||||
|
||||
//YamlResourceImport -
|
||||
func (t *ClusterController) YamlResourceImport(w http.ResponseWriter, r *http.Request) {
|
||||
var yr model.YamlResource
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &yr, nil); !ok {
|
||||
return
|
||||
}
|
||||
ar, err := handler.GetClusterHandler().AppYamlResourceDetailed(yr, true)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
ac, err := handler.GetClusterHandler().AppYamlResourceImport(yr, ar)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, ac)
|
||||
}
|
||||
|
86
api/controller/k8s_attribute.go
Normal file
86
api/controller/k8s_attribute.go
Normal file
@ -0,0 +1,86 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2022-2022 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/api/handler"
|
||||
api_model "github.com/goodrain/rainbond/api/model"
|
||||
ctxutil "github.com/goodrain/rainbond/api/util/ctx"
|
||||
httputil "github.com/goodrain/rainbond/util/http"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// K8sAttributeController -
|
||||
type K8sAttributeController struct{}
|
||||
|
||||
// K8sAttributes -
|
||||
func (k *K8sAttributeController) K8sAttributes(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
k.createK8sAttributes(w, r)
|
||||
case "PUT":
|
||||
k.updateK8sAttributes(w, r)
|
||||
case "DELETE":
|
||||
k.deleteK8sAttributes(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (k *K8sAttributeController) createK8sAttributes(w http.ResponseWriter, r *http.Request) {
|
||||
tenantID := r.Context().Value(ctxutil.ContextKey("tenant_id")).(string)
|
||||
componentID := r.Context().Value(ctxutil.ContextKey("service_id")).(string)
|
||||
var k8sAttr api_model.ComponentK8sAttribute
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &k8sAttr, nil); !ok {
|
||||
httputil.ReturnBcodeError(r, w, fmt.Errorf("k8s attributes is not valid"))
|
||||
return
|
||||
}
|
||||
if err := handler.GetServiceManager().CreateK8sAttribute(tenantID, componentID, &k8sAttr); err != nil {
|
||||
httputil.ReturnBcodeError(r, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (k *K8sAttributeController) updateK8sAttributes(w http.ResponseWriter, r *http.Request) {
|
||||
componentID := r.Context().Value(ctxutil.ContextKey("service_id")).(string)
|
||||
var k8sAttr api_model.ComponentK8sAttribute
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &k8sAttr, nil); !ok {
|
||||
httputil.ReturnBcodeError(r, w, fmt.Errorf("k8s attributes is not valid"))
|
||||
return
|
||||
}
|
||||
if err := handler.GetServiceManager().UpdateK8sAttribute(componentID, &k8sAttr); err != nil {
|
||||
httputil.ReturnBcodeError(r, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (k *K8sAttributeController) deleteK8sAttributes(w http.ResponseWriter, r *http.Request) {
|
||||
componentID := r.Context().Value(ctxutil.ContextKey("service_id")).(string)
|
||||
var req api_model.DeleteK8sAttributeReq
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &req, nil); !ok {
|
||||
httputil.ReturnBcodeError(r, w, fmt.Errorf("k8s attributes is not valid"))
|
||||
return
|
||||
}
|
||||
if err := handler.GetServiceManager().DeleteK8sAttribute(componentID, req.Name); err != nil {
|
||||
httputil.ReturnBcodeError(r, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
@ -61,6 +61,7 @@ type V2Routes struct {
|
||||
PodController
|
||||
ApplicationController
|
||||
RegistryAuthSecretStruct
|
||||
K8sAttributeController
|
||||
}
|
||||
|
||||
//Show test
|
||||
@ -733,6 +734,7 @@ func (t *TenantStruct) UpdateService(w http.ResponseWriter, r *http.Request) {
|
||||
"extend_method": []string{},
|
||||
"app_id": []string{},
|
||||
"k8s_component_name": []string{},
|
||||
"job_strategy": []string{},
|
||||
}
|
||||
data, ok := httputil.ValidatorRequestMapAndErrorResponse(r, w, rules, nil)
|
||||
if !ok {
|
||||
|
@ -1,7 +1,12 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/goodrain/rainbond/api/client/prometheus"
|
||||
|
||||
@ -60,6 +65,59 @@ func (t *TenantStruct) UpdateServiceMonitors(w http.ResponseWriter, r *http.Requ
|
||||
httputil.ReturnSuccess(r, w, tsm)
|
||||
}
|
||||
|
||||
//UploadPackage upload package
|
||||
func (t *TenantStruct) UploadPackage(w http.ResponseWriter, r *http.Request) {
|
||||
eventID := strings.TrimSpace(chi.URLParam(r, "eventID"))
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
if eventID == "" {
|
||||
httputil.ReturnError(r, w, 400, "Failed to parse eventID.")
|
||||
return
|
||||
}
|
||||
logrus.Debug("Start receive upload file: ", eventID)
|
||||
reader, header, err := r.FormFile("packageTarFile")
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to parse upload file: %s", err.Error())
|
||||
httputil.ReturnError(r, w, 501, "Failed to parse upload file.")
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
dirName := fmt.Sprintf("/grdata/package_build/temp/events/%s", eventID)
|
||||
os.MkdirAll(dirName, 0755)
|
||||
|
||||
fileName := fmt.Sprintf("%s/%s", dirName, header.Filename)
|
||||
file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to open file: %s", err.Error())
|
||||
httputil.ReturnError(r, w, 502, "Failed to open file: "+err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
logrus.Debug("Start write file to: ", fileName)
|
||||
if _, err := io.Copy(file, reader); err != nil {
|
||||
logrus.Errorf("Failed to write file:%s", err.Error())
|
||||
httputil.ReturnError(r, w, 503, "Failed to write file: "+err.Error())
|
||||
}
|
||||
|
||||
logrus.Debug("successful write file to: ", fileName)
|
||||
origin := r.Header.Get("Origin")
|
||||
w.Header().Add("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST,OPTIONS")
|
||||
w.Header().Add("Access-Control-Allow-Credentials", "true")
|
||||
w.Header().Add("Access-Control-Allow-Headers", "x-requested-with,Content-Type,X-Custom-Header")
|
||||
httputil.ReturnSuccess(r, w, nil)
|
||||
|
||||
case "OPTIONS":
|
||||
origin := r.Header.Get("Origin")
|
||||
w.Header().Add("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST,OPTIONS")
|
||||
w.Header().Add("Access-Control-Allow-Credentials", "true")
|
||||
w.Header().Add("Access-Control-Allow-Headers", "x-requested-with,Content-Type,X-Custom-Header")
|
||||
httputil.ReturnSuccess(r, w, nil)
|
||||
}
|
||||
}
|
||||
|
||||
//GetMonitorMetrics get monitor metrics
|
||||
func GetMonitorMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
target := r.FormValue("target")
|
||||
|
@ -646,6 +646,9 @@ func (a *ApplicationAction) SyncComponents(app *dbmodel.Application, components
|
||||
if err := GetServiceManager().SyncComponentEndpoints(tx, components); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := GetServiceManager().SyncComponentK8sAttributes(tx, app, components); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(deleteComponentIDs) != 0 {
|
||||
return a.deleteByComponentIDs(tx, app, deleteComponentIDs)
|
||||
}
|
||||
@ -719,7 +722,10 @@ func (a *ApplicationAction) deleteByComponentIDs(tx *gorm.DB, app *dbmodel.Appli
|
||||
if err = db.GetManager().TenantServceAutoscalerRulesDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
return db.GetManager().TenantServceAutoscalerRuleMetricsDaoTransactions(tx).DeleteByRuleIDs(autoScaleRuleIDs)
|
||||
if err = db.GetManager().TenantServceAutoscalerRuleMetricsDaoTransactions(tx).DeleteByRuleIDs(autoScaleRuleIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
return db.GetManager().ComponentK8sAttributeDaoTransactions(tx).DeleteByComponentIDs(componentIDs)
|
||||
}
|
||||
|
||||
// ListAppStatuses -
|
||||
|
@ -3,20 +3,24 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
"github.com/goodrain/rainbond/util/constants"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ClusterHandler -
|
||||
@ -27,13 +31,26 @@ type ClusterHandler interface {
|
||||
MavenSettingUpdate(ctx context.Context, ms *MavenSetting) *util.APIHandleError
|
||||
MavenSettingDelete(ctx context.Context, name string) *util.APIHandleError
|
||||
MavenSettingDetail(ctx context.Context, name string) (*MavenSetting, *util.APIHandleError)
|
||||
GetNamespace(ctx context.Context, content string) ([]string, *util.APIHandleError)
|
||||
GetNamespaceSource(ctx context.Context, content string, namespace string) (map[string]model.LabelResource, *util.APIHandleError)
|
||||
ConvertResource(ctx context.Context, namespace string, lr map[string]model.LabelResource) (map[string]model.ApplicationResource, *util.APIHandleError)
|
||||
ResourceImport(namespace string, as map[string]model.ApplicationResource, eid string) (*model.ReturnResourceImport, *util.APIHandleError)
|
||||
AddAppK8SResource(ctx context.Context, namespace string, appID string, resourceYaml string) ([]*dbmodel.K8sResource, *util.APIHandleError)
|
||||
DeleteAppK8SResource(ctx context.Context, namespace, appID, name, yaml, kind string) *util.APIHandleError
|
||||
UpdateAppK8SResource(ctx context.Context, namespace, appID, name, resourceYaml, kind string) (dbmodel.K8sResource, *util.APIHandleError)
|
||||
SyncAppK8SResources(ctx context.Context, resources *model.SyncResources) ([]*dbmodel.K8sResource, *util.APIHandleError)
|
||||
AppYamlResourceName(yamlResource model.YamlResource) (map[string]model.LabelResource, *util.APIHandleError)
|
||||
AppYamlResourceDetailed(yamlResource model.YamlResource, yamlImport bool) (model.ApplicationResource, *util.APIHandleError)
|
||||
AppYamlResourceImport(yamlResource model.YamlResource, components model.ApplicationResource) (model.AppComponent, *util.APIHandleError)
|
||||
}
|
||||
|
||||
// NewClusterHandler -
|
||||
func NewClusterHandler(clientset *kubernetes.Clientset, RbdNamespace string) ClusterHandler {
|
||||
func NewClusterHandler(clientset *kubernetes.Clientset, RbdNamespace string, config *rest.Config, mapper meta.RESTMapper) ClusterHandler {
|
||||
return &clusterAction{
|
||||
namespace: RbdNamespace,
|
||||
clientset: clientset,
|
||||
config: config,
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,8 +59,11 @@ type clusterAction struct {
|
||||
clientset *kubernetes.Clientset
|
||||
clusterInfoCache *model.ClusterResource
|
||||
cacheTime time.Time
|
||||
config *rest.Config
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
//GetClusterInfo -
|
||||
func (c *clusterAction) GetClusterInfo(ctx context.Context) (*model.ClusterResource, error) {
|
||||
timeout, _ := strconv.Atoi(os.Getenv("CLUSTER_INFO_CACHE_TIME"))
|
||||
if timeout == 0 {
|
||||
@ -332,3 +352,34 @@ func (c *clusterAction) MavenSettingDetail(ctx context.Context, name string) (*M
|
||||
Content: sm.Data["mavensetting"],
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetNamespace Get namespace of the current cluster
|
||||
func (c *clusterAction) GetNamespace(ctx context.Context, content string) ([]string, *util.APIHandleError) {
|
||||
namespaceList, err := c.clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get namespace:%v", err)}
|
||||
}
|
||||
namespaces := new([]string)
|
||||
for _, ns := range namespaceList.Items {
|
||||
if strings.HasPrefix(ns.Name, "kube-") || ns.Name == "rainbond" || ns.Name == "rbd-system" {
|
||||
continue
|
||||
}
|
||||
if labelValue, isRBDNamespace := ns.Labels[constants.ResourceManagedByLabel]; isRBDNamespace && labelValue == "rainbond" && content == "unmanaged" {
|
||||
continue
|
||||
}
|
||||
*namespaces = append(*namespaces, ns.Name)
|
||||
}
|
||||
return *namespaces, nil
|
||||
}
|
||||
|
||||
//MergeMap map去重合并
|
||||
func MergeMap(map1 map[string][]string, map2 map[string][]string) map[string][]string {
|
||||
for k, v := range map1 {
|
||||
if _, ok := map2[k]; ok {
|
||||
map2[k] = append(map2[k], v...)
|
||||
continue
|
||||
}
|
||||
map2[k] = v
|
||||
}
|
||||
return map2
|
||||
}
|
||||
|
493
api/handler/covert_resource.go
Normal file
493
api/handler/covert_resource.go
Normal file
@ -0,0 +1,493 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
v1 "k8s.io/api/autoscaling/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//ConvertResource 处理资源
|
||||
func (c *clusterAction) ConvertResource(ctx context.Context, namespace string, lr map[string]model.LabelResource) (map[string]model.ApplicationResource, *util.APIHandleError) {
|
||||
logrus.Infof("ConvertResource function begin")
|
||||
appsServices := make(map[string]model.ApplicationResource)
|
||||
for label, resource := range lr {
|
||||
c.workloadHandle(ctx, appsServices, resource, namespace, label)
|
||||
}
|
||||
logrus.Infof("ConvertResource function end")
|
||||
return appsServices, nil
|
||||
}
|
||||
|
||||
func (c *clusterAction) workloadHandle(ctx context.Context, cr map[string]model.ApplicationResource, lr model.LabelResource, namespace string, label string) {
|
||||
app := label
|
||||
deployResource := c.workloadDeployments(lr.Workloads.Deployments, namespace)
|
||||
sfsResource := c.workloadStateFulSets(lr.Workloads.StateFulSets, namespace)
|
||||
jobResource := c.workloadJobs(lr.Workloads.Jobs, namespace)
|
||||
cjResource := c.workloadCronJobs(lr.Workloads.CronJobs, namespace)
|
||||
convertResource := append(deployResource, append(sfsResource, append(jobResource, append(cjResource)...)...)...)
|
||||
k8sResources := c.getAppKubernetesResources(ctx, lr.Others, namespace)
|
||||
cr[app] = model.ApplicationResource{
|
||||
ConvertResource: convertResource,
|
||||
KubernetesResources: k8sResources,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clusterAction) workloadDeployments(dmNames []string, namespace string) []model.ConvertResource {
|
||||
var componentsCR []model.ConvertResource
|
||||
for _, dmName := range dmNames {
|
||||
resources, err := c.clientset.AppsV1().Deployments(namespace).Get(context.Background(), dmName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Deployment %v:%v", dmName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
//BasicManagement
|
||||
basic := model.BasicManagement{
|
||||
ResourceType: model.Deployment,
|
||||
Replicas: resources.Spec.Replicas,
|
||||
Memory: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: resources.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(resources.Spec.Template.Spec.Containers[0].Command, resources.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := model.YamlResourceParameter{
|
||||
ComponentsCR: &componentsCR,
|
||||
Basic: basic,
|
||||
Template: resources.Spec.Template,
|
||||
Namespace: namespace,
|
||||
Name: dmName,
|
||||
RsLabel: resources.Labels,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
}
|
||||
return componentsCR
|
||||
}
|
||||
|
||||
func (c *clusterAction) workloadStateFulSets(sfsNames []string, namespace string) []model.ConvertResource {
|
||||
var componentsCR []model.ConvertResource
|
||||
for _, sfsName := range sfsNames {
|
||||
resources, err := c.clientset.AppsV1().StatefulSets(namespace).Get(context.Background(), sfsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Deployment %v:%v", sfsName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
//BasicManagement
|
||||
basic := model.BasicManagement{
|
||||
ResourceType: model.StateFulSet,
|
||||
Replicas: resources.Spec.Replicas,
|
||||
Memory: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: resources.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(resources.Spec.Template.Spec.Containers[0].Command, resources.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := model.YamlResourceParameter{
|
||||
ComponentsCR: &componentsCR,
|
||||
Basic: basic,
|
||||
Template: resources.Spec.Template,
|
||||
Namespace: namespace,
|
||||
Name: sfsName,
|
||||
RsLabel: resources.Labels,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
}
|
||||
return componentsCR
|
||||
}
|
||||
|
||||
func (c *clusterAction) workloadJobs(jobNames []string, namespace string) []model.ConvertResource {
|
||||
var componentsCR []model.ConvertResource
|
||||
for _, jobName := range jobNames {
|
||||
resources, err := c.clientset.BatchV1().Jobs(namespace).Get(context.Background(), jobName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Deployment %v:%v", jobName, err)
|
||||
return nil
|
||||
}
|
||||
var BackoffLimit, Parallelism, ActiveDeadlineSeconds, Completions string
|
||||
if resources.Spec.BackoffLimit != nil {
|
||||
BackoffLimit = fmt.Sprintf("%v", *resources.Spec.BackoffLimit)
|
||||
}
|
||||
if resources.Spec.Parallelism != nil {
|
||||
Parallelism = fmt.Sprintf("%v", *resources.Spec.Parallelism)
|
||||
}
|
||||
if resources.Spec.ActiveDeadlineSeconds != nil {
|
||||
ActiveDeadlineSeconds = fmt.Sprintf("%v", *resources.Spec.ActiveDeadlineSeconds)
|
||||
}
|
||||
if resources.Spec.Completions != nil {
|
||||
Completions = fmt.Sprintf("%v", *resources.Spec.Completions)
|
||||
}
|
||||
job := model.JobStrategy{
|
||||
Schedule: resources.Spec.Template.Spec.SchedulerName,
|
||||
BackoffLimit: BackoffLimit,
|
||||
Parallelism: Parallelism,
|
||||
ActiveDeadlineSeconds: ActiveDeadlineSeconds,
|
||||
Completions: Completions,
|
||||
}
|
||||
//BasicManagement
|
||||
basic := model.BasicManagement{
|
||||
ResourceType: model.Job,
|
||||
Replicas: resources.Spec.Completions,
|
||||
Memory: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: resources.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: resources.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(resources.Spec.Template.Spec.Containers[0].Command, resources.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
JobStrategy: job,
|
||||
}
|
||||
parameter := model.YamlResourceParameter{
|
||||
ComponentsCR: &componentsCR,
|
||||
Basic: basic,
|
||||
Template: resources.Spec.Template,
|
||||
Namespace: namespace,
|
||||
Name: jobName,
|
||||
RsLabel: resources.Labels,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
}
|
||||
return componentsCR
|
||||
}
|
||||
|
||||
func (c *clusterAction) workloadCronJobs(cjNames []string, namespace string) []model.ConvertResource {
|
||||
var componentsCR []model.ConvertResource
|
||||
for _, cjName := range cjNames {
|
||||
resources, err := c.clientset.BatchV1beta1().CronJobs(namespace).Get(context.Background(), cjName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Deployment %v:%v", cjName, err)
|
||||
return nil
|
||||
}
|
||||
BackoffLimit, Parallelism, ActiveDeadlineSeconds, Completions := "", "", "", ""
|
||||
if resources.Spec.JobTemplate.Spec.BackoffLimit != nil {
|
||||
BackoffLimit = fmt.Sprintf("%v", *resources.Spec.JobTemplate.Spec.BackoffLimit)
|
||||
}
|
||||
if resources.Spec.JobTemplate.Spec.Parallelism != nil {
|
||||
Parallelism = fmt.Sprintf("%v", *resources.Spec.JobTemplate.Spec.Parallelism)
|
||||
}
|
||||
if resources.Spec.JobTemplate.Spec.ActiveDeadlineSeconds != nil {
|
||||
ActiveDeadlineSeconds = fmt.Sprintf("%v", *resources.Spec.JobTemplate.Spec.ActiveDeadlineSeconds)
|
||||
}
|
||||
if resources.Spec.JobTemplate.Spec.Completions != nil {
|
||||
Completions = fmt.Sprintf("%v", *resources.Spec.JobTemplate.Spec.Completions)
|
||||
}
|
||||
job := model.JobStrategy{
|
||||
Schedule: resources.Spec.Schedule,
|
||||
BackoffLimit: BackoffLimit,
|
||||
Parallelism: Parallelism,
|
||||
ActiveDeadlineSeconds: ActiveDeadlineSeconds,
|
||||
Completions: Completions,
|
||||
}
|
||||
//BasicManagement
|
||||
basic := model.BasicManagement{
|
||||
ResourceType: model.CronJob,
|
||||
Replicas: resources.Spec.JobTemplate.Spec.Completions,
|
||||
Memory: resources.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: resources.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: resources.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(resources.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command, resources.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
JobStrategy: job,
|
||||
}
|
||||
parameter := model.YamlResourceParameter{
|
||||
ComponentsCR: &componentsCR,
|
||||
Basic: basic,
|
||||
Template: resources.Spec.JobTemplate.Spec.Template,
|
||||
Namespace: namespace,
|
||||
Name: cjName,
|
||||
RsLabel: resources.Labels,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
}
|
||||
return componentsCR
|
||||
}
|
||||
|
||||
func (c *clusterAction) getAppKubernetesResources(ctx context.Context, others model.OtherResource, namespace string) []dbmodel.K8sResource {
|
||||
var k8sResources []dbmodel.K8sResource
|
||||
servicesMap := make(map[string]corev1.Service)
|
||||
servicesList, err := c.clientset.CoreV1().Services(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get services error:%v", namespace, err)
|
||||
}
|
||||
if len(others.Services) != 0 && err == nil {
|
||||
for _, services := range servicesList.Items {
|
||||
servicesMap[services.Name] = services
|
||||
}
|
||||
for _, servicesName := range others.Services {
|
||||
services, _ := servicesMap[servicesName]
|
||||
services.Kind = model.Service
|
||||
services.Status = corev1.ServiceStatus{}
|
||||
services.APIVersion = "v1"
|
||||
services.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", services)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v service:%v error: %v", namespace, services.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: services.Name,
|
||||
Kind: model.Service,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pvcMap := make(map[string]corev1.PersistentVolumeClaim)
|
||||
pvcList, err := c.clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get pvc error:%v", namespace, err)
|
||||
}
|
||||
if len(others.PVC) != 0 && err == nil {
|
||||
for _, pvc := range pvcList.Items {
|
||||
pvcMap[pvc.Name] = pvc
|
||||
}
|
||||
for _, pvcName := range others.PVC {
|
||||
pvc, _ := pvcMap[pvcName]
|
||||
pvc.Status = corev1.PersistentVolumeClaimStatus{}
|
||||
pvc.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
pvc.Kind = model.PVC
|
||||
pvc.APIVersion = "v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", pvc)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v pvc:%v error: %v", namespace, pvc.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: pvc.Name,
|
||||
Kind: model.PVC,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ingressMap := make(map[string]networkingv1.Ingress)
|
||||
ingressList, err := c.clientset.NetworkingV1().Ingresses(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get ingresses error:%v", namespace, err)
|
||||
}
|
||||
if len(others.Ingresses) != 0 && err == nil {
|
||||
for _, ingress := range ingressList.Items {
|
||||
ingressMap[ingress.Name] = ingress
|
||||
}
|
||||
for _, ingressName := range others.Ingresses {
|
||||
ingresses, _ := ingressMap[ingressName]
|
||||
ingresses.Status = networkingv1.IngressStatus{}
|
||||
ingresses.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
ingresses.Kind = model.Ingress
|
||||
ingresses.APIVersion = "networking.k8s.io/v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", ingresses)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v ingresses:%v error: %v", namespace, ingresses.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: ingresses.Name,
|
||||
Kind: model.Ingress,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
networkPoliciesMap := make(map[string]networkingv1.NetworkPolicy)
|
||||
networkPoliciesList, err := c.clientset.NetworkingV1().NetworkPolicies(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get NetworkPolicies error:%v", namespace, err)
|
||||
}
|
||||
if len(others.NetworkPolicies) != 0 && err == nil {
|
||||
for _, networkPolicies := range networkPoliciesList.Items {
|
||||
networkPoliciesMap[networkPolicies.Name] = networkPolicies
|
||||
}
|
||||
for _, networkPoliciesName := range others.NetworkPolicies {
|
||||
networkPolicies, _ := networkPoliciesMap[networkPoliciesName]
|
||||
networkPolicies.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
networkPolicies.Kind = model.NetworkPolicy
|
||||
networkPolicies.APIVersion = "networking.k8s.io/v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", networkPolicies)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v NetworkPolicies:%v error: %v", namespace, networkPolicies.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: networkPolicies.Name,
|
||||
Kind: model.NetworkPolicy,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cmMap := make(map[string]corev1.ConfigMap)
|
||||
cmList, err := c.clientset.CoreV1().ConfigMaps(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get ConfigMaps error:%v", namespace, err)
|
||||
}
|
||||
if len(others.ConfigMaps) != 0 && err == nil {
|
||||
for _, cm := range cmList.Items {
|
||||
cmMap[cm.Name] = cm
|
||||
}
|
||||
for _, configMapsName := range others.ConfigMaps {
|
||||
configMaps, _ := cmMap[configMapsName]
|
||||
configMaps.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
configMaps.Kind = model.ConfigMap
|
||||
configMaps.APIVersion = "v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", configMaps)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v ConfigMaps:%v error: %v", namespace, configMaps.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: configMaps.Name,
|
||||
Kind: model.ConfigMap,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
secretsMap := make(map[string]corev1.Secret)
|
||||
secretsList, err := c.clientset.CoreV1().Secrets(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get Secrets error:%v", namespace, err)
|
||||
}
|
||||
if len(others.Secrets) != 0 && err == nil {
|
||||
for _, secrets := range secretsList.Items {
|
||||
secretsMap[secrets.Name] = secrets
|
||||
}
|
||||
for _, secretsName := range others.Secrets {
|
||||
secrets, _ := secretsMap[secretsName]
|
||||
secrets.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
secrets.Kind = model.Secret
|
||||
secrets.APIVersion = "v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", secrets)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v Secrets:%v error: %v", namespace, secrets.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: secrets.Name,
|
||||
Kind: model.Secret,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
serviceAccountsMap := make(map[string]corev1.ServiceAccount)
|
||||
serviceAccountsList, err := c.clientset.CoreV1().ServiceAccounts(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get ServiceAccounts error:%v", namespace, err)
|
||||
}
|
||||
if len(others.ServiceAccounts) != 0 && err == nil {
|
||||
for _, serviceAccounts := range serviceAccountsList.Items {
|
||||
serviceAccountsMap[serviceAccounts.Name] = serviceAccounts
|
||||
}
|
||||
for _, serviceAccountsName := range others.ServiceAccounts {
|
||||
serviceAccounts, _ := serviceAccountsMap[serviceAccountsName]
|
||||
serviceAccounts.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
serviceAccounts.Kind = model.ServiceAccount
|
||||
serviceAccounts.APIVersion = "v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", serviceAccounts)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v ServiceAccounts:%v error: %v", namespace, serviceAccounts.Name, err)
|
||||
continue
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: serviceAccounts.Name,
|
||||
Kind: model.ServiceAccount,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
roleBindingsMap := make(map[string]rbacv1.RoleBinding)
|
||||
roleBindingsList, _ := c.clientset.RbacV1().RoleBindings(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get RoleBindings error:%v", namespace, err)
|
||||
}
|
||||
if len(others.RoleBindings) != 0 && err == nil {
|
||||
for _, roleBindings := range roleBindingsList.Items {
|
||||
roleBindingsMap[roleBindings.Name] = roleBindings
|
||||
}
|
||||
for _, roleBindingsName := range others.RoleBindings {
|
||||
roleBindings, _ := roleBindingsMap[roleBindingsName]
|
||||
roleBindings.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
roleBindings.Kind = model.RoleBinding
|
||||
roleBindings.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", roleBindings)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v RoleBindings:%v error: %v", namespace, roleBindings.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: roleBindings.Name,
|
||||
Kind: model.RoleBinding,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
hpaMap := make(map[string]v1.HorizontalPodAutoscaler)
|
||||
hpaList, _ := c.clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get HorizontalPodAutoscalers error:%v", namespace, err)
|
||||
}
|
||||
if len(others.HorizontalPodAutoscalers) != 0 && err == nil {
|
||||
for _, hpa := range hpaList.Items {
|
||||
hpaMap[hpa.Name] = hpa
|
||||
}
|
||||
for _, hpaName := range others.HorizontalPodAutoscalers {
|
||||
hpa, _ := hpaMap[hpaName]
|
||||
hpa.Status = v1.HorizontalPodAutoscalerStatus{}
|
||||
hpa.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
hpa.Kind = model.HorizontalPodAutoscaler
|
||||
hpa.APIVersion = "autoscaling/v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", hpa)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v HorizontalPodAutoscalers:%v error: %v", namespace, hpa.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: hpa.Name,
|
||||
Kind: model.HorizontalPodAutoscaler,
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: 1,
|
||||
ErrorOverview: "创建成功",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
rolesMap := make(map[string]rbacv1.Role)
|
||||
rolesList, err := c.clientset.RbacV1().Roles(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v get roles error:%v", namespace, err)
|
||||
}
|
||||
if len(others.Roles) != 0 && err == nil {
|
||||
for _, roles := range rolesList.Items {
|
||||
rolesMap[roles.Name] = roles
|
||||
}
|
||||
for _, rolesName := range others.Roles {
|
||||
roles, _ := rolesMap[rolesName]
|
||||
roles.Kind = model.Role
|
||||
roles.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", roles)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v roles:%v error: %v", namespace, roles.Name, err)
|
||||
}
|
||||
k8sResources = append(k8sResources, dbmodel.K8sResource{
|
||||
Name: roles.Name,
|
||||
Kind: model.Role,
|
||||
Content: kubernetesResourcesYAML,
|
||||
ErrorOverview: "创建成功",
|
||||
State: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
return k8sResources
|
||||
}
|
530
api/handler/get_namespace_resource_name.go
Normal file
530
api/handler/get_namespace_resource_name.go
Normal file
@ -0,0 +1,530 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
//GetNamespaceSource Get all resources in the current namespace
|
||||
func (c *clusterAction) GetNamespaceSource(ctx context.Context, content string, namespace string) (map[string]model.LabelResource, *util.APIHandleError) {
|
||||
logrus.Infof("GetNamespaceSource function begin")
|
||||
//存储workloads们的ConfigMap
|
||||
cmsMap := make(map[string][]string)
|
||||
//存储workloads们的secrets
|
||||
secretsMap := make(map[string][]string)
|
||||
deployments, cmMap, secretMap := c.getResourceName(context.Background(), namespace, content, model.Deployment)
|
||||
if len(cmsMap) != 0 {
|
||||
cmsMap = MergeMap(cmMap, cmsMap)
|
||||
}
|
||||
if len(secretMap) != 0 {
|
||||
secretsMap = MergeMap(secretMap, secretsMap)
|
||||
}
|
||||
jobs, cmMap, secretMap := c.getResourceName(ctx, namespace, content, model.Job)
|
||||
if len(cmsMap) != 0 {
|
||||
cmsMap = MergeMap(cmMap, cmsMap)
|
||||
}
|
||||
if len(secretMap) != 0 {
|
||||
secretsMap = MergeMap(secretMap, secretsMap)
|
||||
}
|
||||
cronJobs, cmMap, secretMap := c.getResourceName(ctx, namespace, content, model.CronJob)
|
||||
if len(cmsMap) != 0 {
|
||||
cmsMap = MergeMap(cmMap, cmsMap)
|
||||
}
|
||||
if len(secretMap) != 0 {
|
||||
secretsMap = MergeMap(secretMap, secretsMap)
|
||||
}
|
||||
stateFulSets, cmMap, secretMap := c.getResourceName(ctx, namespace, content, model.StateFulSet)
|
||||
if len(cmsMap) != 0 {
|
||||
cmsMap = MergeMap(cmMap, cmsMap)
|
||||
}
|
||||
if len(secretMap) != 0 {
|
||||
secretsMap = MergeMap(secretMap, secretsMap)
|
||||
}
|
||||
processWorkloads := model.LabelWorkloadsResourceProcess{
|
||||
Deployments: deployments,
|
||||
Jobs: jobs,
|
||||
CronJobs: cronJobs,
|
||||
StateFulSets: stateFulSets,
|
||||
}
|
||||
services, _, _ := c.getResourceName(ctx, namespace, content, model.Service)
|
||||
pvc, _, _ := c.getResourceName(ctx, namespace, content, model.PVC)
|
||||
ingresses, _, _ := c.getResourceName(ctx, namespace, content, model.Ingress)
|
||||
networkPolicies, _, _ := c.getResourceName(ctx, namespace, content, model.NetworkPolicy)
|
||||
cms, _, _ := c.getResourceName(ctx, namespace, content, model.ConfigMap)
|
||||
secrets, _, _ := c.getResourceName(ctx, namespace, content, model.Secret)
|
||||
serviceAccounts, _, _ := c.getResourceName(ctx, namespace, content, model.ServiceAccount)
|
||||
roleBindings, _, _ := c.getResourceName(ctx, namespace, content, model.RoleBinding)
|
||||
horizontalPodAutoscalers, _, _ := c.getResourceName(ctx, namespace, content, model.HorizontalPodAutoscaler)
|
||||
roles, _, _ := c.getResourceName(ctx, namespace, content, model.Role)
|
||||
processOthers := model.LabelOthersResourceProcess{
|
||||
Services: services,
|
||||
PVC: pvc,
|
||||
Ingresses: ingresses,
|
||||
NetworkPolicies: networkPolicies,
|
||||
ConfigMaps: MergeMap(cmsMap, cms),
|
||||
Secrets: MergeMap(secretsMap, secrets),
|
||||
ServiceAccounts: serviceAccounts,
|
||||
RoleBindings: roleBindings,
|
||||
HorizontalPodAutoscalers: horizontalPodAutoscalers,
|
||||
Roles: roles,
|
||||
}
|
||||
labelResource := resourceProcessing(processWorkloads, processOthers)
|
||||
logrus.Infof("GetNamespaceSource function end")
|
||||
return labelResource, nil
|
||||
}
|
||||
|
||||
//resourceProcessing 将处理好的资源类型数据格式再加工成可作为返回值的数据。
|
||||
func resourceProcessing(processWorkloads model.LabelWorkloadsResourceProcess, processOthers model.LabelOthersResourceProcess) map[string]model.LabelResource {
|
||||
labelResource := make(map[string]model.LabelResource)
|
||||
for label, deployments := range processWorkloads.Deployments {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Workloads.Deployments = deployments
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Workloads: model.WorkLoadsResource{
|
||||
Deployments: deployments,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, jobs := range processWorkloads.Jobs {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Workloads.Jobs = jobs
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Workloads: model.WorkLoadsResource{
|
||||
Jobs: jobs,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
for label, cronJobs := range processWorkloads.CronJobs {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Workloads.CronJobs = cronJobs
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Workloads: model.WorkLoadsResource{
|
||||
CronJobs: cronJobs,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, stateFulSets := range processWorkloads.StateFulSets {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Workloads.StateFulSets = stateFulSets
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Workloads: model.WorkLoadsResource{
|
||||
StateFulSets: stateFulSets,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, service := range processOthers.Services {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.Services = service
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
Services: service,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
for label, pvc := range processOthers.PVC {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.PVC = pvc
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
PVC: pvc,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
for label, ingresses := range processOthers.Ingresses {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.Ingresses = ingresses
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
Ingresses: ingresses,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, networkPolicies := range processOthers.NetworkPolicies {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.NetworkPolicies = networkPolicies
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
NetworkPolicies: networkPolicies,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, configMaps := range processOthers.ConfigMaps {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.ConfigMaps = configMaps
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
ConfigMaps: configMaps,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, secrets := range processOthers.Secrets {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.Secrets = secrets
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
Secrets: secrets,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, serviceAccounts := range processOthers.ServiceAccounts {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.ServiceAccounts = serviceAccounts
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
ServiceAccounts: serviceAccounts,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, roleBindings := range processOthers.RoleBindings {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.RoleBindings = roleBindings
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
RoleBindings: roleBindings,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, horizontalPodAutoscalers := range processOthers.HorizontalPodAutoscalers {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.HorizontalPodAutoscalers = horizontalPodAutoscalers
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
HorizontalPodAutoscalers: horizontalPodAutoscalers,
|
||||
},
|
||||
}
|
||||
}
|
||||
for label, roles := range processOthers.Roles {
|
||||
if val, ok := labelResource[label]; ok {
|
||||
val.Others.Roles = roles
|
||||
labelResource[label] = val
|
||||
continue
|
||||
}
|
||||
labelResource[label] = model.LabelResource{
|
||||
Others: model.OtherResource{
|
||||
Roles: roles,
|
||||
},
|
||||
}
|
||||
}
|
||||
return labelResource
|
||||
}
|
||||
|
||||
//Resource -
|
||||
type Resource struct {
|
||||
ObjectMeta metav1.ObjectMeta
|
||||
Template corev1.PodTemplateSpec
|
||||
}
|
||||
|
||||
//getResourceName 将指定资源类型按照【label名】:[]{资源名...}处理后返回
|
||||
func (c *clusterAction) getResourceName(ctx context.Context, namespace string, content string, resourcesType string) (map[string][]string, map[string][]string, map[string][]string) {
|
||||
resourceName := make(map[string][]string)
|
||||
var tempResources []*Resource
|
||||
isWorkloads := false
|
||||
cmMap := make(map[string][]string)
|
||||
secretMap := make(map[string][]string)
|
||||
switch resourcesType {
|
||||
case model.Deployment:
|
||||
resources, err := c.clientset.AppsV1().Deployments(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Deployment list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta, Template: dm.Spec.Template})
|
||||
}
|
||||
isWorkloads = true
|
||||
case model.Job:
|
||||
resources, err := c.clientset.BatchV1().Jobs(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Job list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
if dm.OwnerReferences != nil {
|
||||
if dm.OwnerReferences[0].Kind == model.CronJob {
|
||||
continue
|
||||
}
|
||||
}
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta, Template: dm.Spec.Template})
|
||||
}
|
||||
isWorkloads = true
|
||||
case model.CronJob:
|
||||
resources, err := c.clientset.BatchV1beta1().CronJobs(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get CronJob list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta, Template: dm.Spec.JobTemplate.Spec.Template})
|
||||
}
|
||||
isWorkloads = true
|
||||
case model.StateFulSet:
|
||||
resources, err := c.clientset.AppsV1().StatefulSets(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get StateFulSets list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta, Template: dm.Spec.Template})
|
||||
}
|
||||
isWorkloads = true
|
||||
case model.Service:
|
||||
resources, err := c.clientset.CoreV1().Services(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Services list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.PVC:
|
||||
resources, err := c.clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get PersistentVolumeClaims list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.Ingress:
|
||||
resources, err := c.clientset.NetworkingV1().Ingresses(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Ingresses list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.NetworkPolicy:
|
||||
resources, err := c.clientset.NetworkingV1().NetworkPolicies(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get NetworkPolicies list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.ConfigMap:
|
||||
resources, err := c.clientset.CoreV1().ConfigMaps(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get ConfigMaps list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.Secret:
|
||||
resources, err := c.clientset.CoreV1().Secrets(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Secrets list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.ServiceAccount:
|
||||
resources, err := c.clientset.CoreV1().ServiceAccounts(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get ServiceAccounts list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.RoleBinding:
|
||||
resources, err := c.clientset.RbacV1().RoleBindings(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get RoleBindings list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
case model.HorizontalPodAutoscaler:
|
||||
resources, err := c.clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get HorizontalPodAutoscalers list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, hpa := range resources.Items {
|
||||
rbdResource := false
|
||||
labels := make(map[string]string)
|
||||
switch hpa.Spec.ScaleTargetRef.Kind {
|
||||
case model.Deployment:
|
||||
deploy, err := c.clientset.AppsV1().Deployments(namespace).Get(context.Background(), hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("The bound deployment does not exist:%v", err)
|
||||
}
|
||||
if hpa.ObjectMeta.Labels["creator"] == "Rainbond" {
|
||||
rbdResource = true
|
||||
}
|
||||
labels = deploy.ObjectMeta.Labels
|
||||
case model.StateFulSet:
|
||||
ss, err := c.clientset.AppsV1().StatefulSets(namespace).Get(context.Background(), hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("The bound deployment does not exist:%v", err)
|
||||
}
|
||||
if hpa.ObjectMeta.Labels["creator"] == "Rainbond" {
|
||||
rbdResource = true
|
||||
}
|
||||
labels = ss.ObjectMeta.Labels
|
||||
}
|
||||
var app string
|
||||
if content == "unmanaged" && rbdResource {
|
||||
continue
|
||||
}
|
||||
app = labels["app"]
|
||||
if labels["app.kubernetes.io/name"] != "" {
|
||||
app = labels["app.kubernetes.io/name"]
|
||||
}
|
||||
if app == "" {
|
||||
app = "unclassified"
|
||||
}
|
||||
if _, ok := resourceName[app]; ok {
|
||||
resourceName[app] = append(resourceName[app], hpa.Name)
|
||||
} else {
|
||||
resourceName[app] = []string{hpa.Name}
|
||||
}
|
||||
}
|
||||
return resourceName, nil, nil
|
||||
case model.Role:
|
||||
resources, err := c.clientset.RbacV1().Roles(namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Roles list:%v", err)
|
||||
return nil, cmMap, secretMap
|
||||
}
|
||||
for _, dm := range resources.Items {
|
||||
tempResources = append(tempResources, &Resource{ObjectMeta: dm.ObjectMeta})
|
||||
}
|
||||
}
|
||||
//这一块是统一处理资源,按label划分出来
|
||||
for _, rs := range tempResources {
|
||||
if content == "unmanaged" && rs.ObjectMeta.Labels["creator"] == "Rainbond" {
|
||||
continue
|
||||
}
|
||||
app := rs.ObjectMeta.Labels["app"]
|
||||
if rs.ObjectMeta.Labels["app.kubernetes.io/name"] != "" {
|
||||
app = rs.ObjectMeta.Labels["app.kubernetes.io/name"]
|
||||
}
|
||||
if app == "" {
|
||||
app = "unclassified"
|
||||
}
|
||||
//如果是Workloads类型的资源需要检查其内部configmap、secret、PVC(防止没有这三种资源没有label但是用到了)
|
||||
if isWorkloads {
|
||||
cmList, secretList := c.replenishLabel(ctx, rs, namespace, app)
|
||||
if _, ok := cmMap[app]; ok {
|
||||
cmMap[app] = append(cmMap[app], cmList...)
|
||||
} else {
|
||||
cmMap[app] = cmList
|
||||
}
|
||||
if _, ok := secretMap[app]; ok {
|
||||
secretMap[app] = append(secretMap[app], secretList...)
|
||||
} else {
|
||||
secretMap[app] = secretList
|
||||
}
|
||||
}
|
||||
if _, ok := resourceName[app]; ok {
|
||||
resourceName[app] = append(resourceName[app], rs.ObjectMeta.Name)
|
||||
} else {
|
||||
resourceName[app] = []string{rs.ObjectMeta.Name}
|
||||
}
|
||||
}
|
||||
return resourceName, cmMap, secretMap
|
||||
}
|
||||
|
||||
//replenishLabel 获取workloads资源上携带的ConfigMap和secret,以及把pvc加上标签。
|
||||
func (c *clusterAction) replenishLabel(ctx context.Context, resource *Resource, namespace string, app string) ([]string, []string) {
|
||||
var cmList []string
|
||||
var secretList []string
|
||||
resourceVolume := resource.Template.Spec.Volumes
|
||||
for _, volume := range resourceVolume {
|
||||
if pvc := volume.PersistentVolumeClaim; pvc != nil {
|
||||
PersistentVolumeClaims, err := c.clientset.CoreV1().PersistentVolumeClaims(namespace).Get(context.Background(), pvc.ClaimName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get PersistentVolumeClaims %s/%s:%v", namespace, pvc.ClaimName, err)
|
||||
}
|
||||
if PersistentVolumeClaims.Labels == nil {
|
||||
PersistentVolumeClaims.Labels = make(map[string]string)
|
||||
}
|
||||
if _, ok := PersistentVolumeClaims.Labels["app"]; !ok {
|
||||
if _, ok := PersistentVolumeClaims.Labels["app.kubernetes.io/name"]; !ok {
|
||||
PersistentVolumeClaims.Labels["app"] = app
|
||||
}
|
||||
}
|
||||
_, err = c.clientset.CoreV1().PersistentVolumeClaims(namespace).Update(context.Background(), PersistentVolumeClaims, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("PersistentVolumeClaims label update error:%v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if cm := volume.ConfigMap; cm != nil {
|
||||
cm, err := c.clientset.CoreV1().ConfigMaps(namespace).Get(context.Background(), cm.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get ConfigMap:%v", err)
|
||||
}
|
||||
if _, ok := cm.Labels["app"]; !ok {
|
||||
if _, ok := cm.Labels["app.kubernetes.io/name"]; !ok {
|
||||
cmList = append(cmList, cm.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if secret := volume.Secret; secret != nil {
|
||||
secret, err := c.clientset.CoreV1().Secrets(namespace).Get(context.Background(), secret.SecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get Scret:%v", err)
|
||||
}
|
||||
if _, ok := secret.Labels["app"]; !ok {
|
||||
if _, ok := secret.Labels["app.kubernetes.io/name"]; !ok {
|
||||
cmList = append(cmList, secret.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cmList, secretList
|
||||
}
|
@ -30,7 +30,9 @@ import (
|
||||
etcdutil "github.com/goodrain/rainbond/util/etcd"
|
||||
"github.com/goodrain/rainbond/worker/client"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
@ -42,6 +44,8 @@ func InitHandle(conf option.Config,
|
||||
kubeClient *kubernetes.Clientset,
|
||||
rainbondClient versioned.Interface,
|
||||
k8sClient k8sclient.Client,
|
||||
config *rest.Config,
|
||||
mapper meta.RESTMapper,
|
||||
) error {
|
||||
mq := api_db.MQManager{
|
||||
EtcdClientArgs: etcdClientArgs,
|
||||
@ -80,7 +84,7 @@ func InitHandle(conf option.Config,
|
||||
batchOperationHandler = CreateBatchOperationHandler(mqClient, statusCli, operationHandler)
|
||||
defaultAppRestoreHandler = NewAppRestoreHandler()
|
||||
defPodHandler = NewPodHandler(statusCli)
|
||||
defClusterHandler = NewClusterHandler(kubeClient, conf.RbdNamespace)
|
||||
defClusterHandler = NewClusterHandler(kubeClient, conf.RbdNamespace, config, mapper)
|
||||
defaultVolumeTypeHandler = CreateVolumeTypeManger(statusCli)
|
||||
defaultEtcdHandler = NewEtcdHandler(etcdcli)
|
||||
defaultmonitorHandler = NewMonitorHandler(prometheusCli)
|
||||
|
44
api/handler/k8s_attribute.go
Normal file
44
api/handler/k8s_attribute.go
Normal file
@ -0,0 +1,44 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2022-2022 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
api_model "github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
)
|
||||
|
||||
// CreateK8sAttribute -
|
||||
func (s *ServiceAction) CreateK8sAttribute(tenantID, componentID string, k8sAttr *api_model.ComponentK8sAttribute) error {
|
||||
return db.GetManager().ComponentK8sAttributeDao().AddModel(k8sAttr.DbModel(tenantID, componentID))
|
||||
}
|
||||
|
||||
// UpdateK8sAttribute -
|
||||
func (s *ServiceAction) UpdateK8sAttribute(componentID string, k8sAttributes *api_model.ComponentK8sAttribute) error {
|
||||
attr, err := db.GetManager().ComponentK8sAttributeDao().GetByComponentIDAndName(componentID, k8sAttributes.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attr.AttributeValue = k8sAttributes.AttributeValue
|
||||
return db.GetManager().ComponentK8sAttributeDao().UpdateModel(attr)
|
||||
}
|
||||
|
||||
// DeleteK8sAttribute -
|
||||
func (s *ServiceAction) DeleteK8sAttribute(componentID, name string) error {
|
||||
return db.GetManager().ComponentK8sAttributeDao().DeleteByComponentIDAndName(componentID, name)
|
||||
}
|
249
api/handler/resource.go
Normal file
249
api/handler/resource.go
Normal file
@ -0,0 +1,249 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
yamlt "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
//AddAppK8SResource -
|
||||
func (c *clusterAction) AddAppK8SResource(ctx context.Context, namespace string, appID string, resourceYaml string) ([]*dbmodel.K8sResource, *util.APIHandleError) {
|
||||
logrus.Info("begin AddAppK8SResource")
|
||||
resourceObjects := c.HandleResourceYaml([]byte(resourceYaml), namespace, "create", "")
|
||||
var resourceList []*dbmodel.K8sResource
|
||||
for _, resourceObject := range resourceObjects {
|
||||
resource := resourceObject
|
||||
if resourceObject.State == model.CreateError {
|
||||
rsYaml := resourceYaml
|
||||
if resourceObject.Resource != nil {
|
||||
rsYaml, _ = ObjectToJSONORYaml("yaml", resourceObject.Resource)
|
||||
}
|
||||
resourceList = append(resourceList, &dbmodel.K8sResource{
|
||||
AppID: appID,
|
||||
Name: "未识别",
|
||||
Kind: "未识别",
|
||||
Content: rsYaml,
|
||||
ErrorOverview: resource.ErrorOverview,
|
||||
State: resource.State,
|
||||
})
|
||||
} else {
|
||||
rsYaml, _ := ObjectToJSONORYaml("yaml", resourceObject.Resource)
|
||||
resourceList = append(resourceList, &dbmodel.K8sResource{
|
||||
AppID: appID,
|
||||
Name: resource.Resource.GetName(),
|
||||
Kind: resource.Resource.GetKind(),
|
||||
Content: rsYaml,
|
||||
ErrorOverview: resource.ErrorOverview,
|
||||
State: resource.State,
|
||||
})
|
||||
err := db.GetManager().K8sResourceDao().CreateK8sResourceInBatch(resourceList)
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 400, Err: fmt.Errorf("CreateK8sResource %v", err)}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resourceList, nil
|
||||
}
|
||||
|
||||
//UpdateAppK8SResource -
|
||||
func (c *clusterAction) UpdateAppK8SResource(ctx context.Context, namespace, appID, name, resourceYaml, kind string) (dbmodel.K8sResource, *util.APIHandleError) {
|
||||
logrus.Info("begin UpdateAppK8SResource")
|
||||
rs, err := db.GetManager().K8sResourceDao().GetK8sResourceByNameInBatch(appID, name, kind)
|
||||
if err != nil {
|
||||
return dbmodel.K8sResource{}, &util.APIHandleError{Code: 400, Err: fmt.Errorf("get k8s resource %v", err)}
|
||||
}
|
||||
resourceObjects := c.HandleResourceYaml([]byte(resourceYaml), namespace, "update", name)
|
||||
var rsYaml string
|
||||
if resourceObjects[0].State == 4 {
|
||||
rsYaml = resourceYaml
|
||||
rs[0].State = resourceObjects[0].State
|
||||
rs[0].ErrorOverview = resourceObjects[0].ErrorOverview
|
||||
rs[0].Content = rsYaml
|
||||
db.GetManager().K8sResourceDao().UpdateModel(&rs[0])
|
||||
} else {
|
||||
rsYaml, _ = ObjectToJSONORYaml("yaml", resourceObjects[0].Resource)
|
||||
rs[0].State = resourceObjects[0].State
|
||||
rs[0].ErrorOverview = resourceObjects[0].ErrorOverview
|
||||
rs[0].Content = rsYaml
|
||||
db.GetManager().K8sResourceDao().UpdateModel(&rs[0])
|
||||
}
|
||||
return rs[0], nil
|
||||
}
|
||||
|
||||
//DeleteAppK8SResource -
|
||||
func (c *clusterAction) DeleteAppK8SResource(ctx context.Context, namespace, appID, name, resourceYaml, kind string) *util.APIHandleError {
|
||||
logrus.Info("begin DeleteAppK8SResource")
|
||||
c.HandleResourceYaml([]byte(resourceYaml), namespace, "delete", name)
|
||||
err := db.GetManager().K8sResourceDao().DeleteK8sResourceInBatch(appID, name, kind)
|
||||
if err != nil {
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("DeleteAppK8SResource %v", err)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncAppK8SResources -
|
||||
func (c *clusterAction) SyncAppK8SResources(ctx context.Context, req *model.SyncResources) ([]*dbmodel.K8sResource, *util.APIHandleError) {
|
||||
// Only Add
|
||||
logrus.Info("begin SyncAppK8SResource")
|
||||
var resourceList []*dbmodel.K8sResource
|
||||
for _, k8sResource := range req.K8sResources {
|
||||
resourceObjects := c.HandleResourceYaml([]byte(k8sResource.ResourceYaml), k8sResource.Namespace, "re-create", k8sResource.Name)
|
||||
if len(resourceObjects) > 1 {
|
||||
logrus.Warningf("SyncAppK8SResources resourceObjects [%s] too much, ignore it", k8sResource.Name)
|
||||
continue
|
||||
}
|
||||
if len(resourceObjects) == 1 {
|
||||
resourceList = append(resourceList, &dbmodel.K8sResource{
|
||||
AppID: k8sResource.AppID,
|
||||
Name: k8sResource.Name,
|
||||
Kind: k8sResource.Kind,
|
||||
Content: k8sResource.ResourceYaml,
|
||||
ErrorOverview: resourceObjects[0].ErrorOverview,
|
||||
State: resourceObjects[0].State,
|
||||
})
|
||||
}
|
||||
}
|
||||
err := db.GetManager().K8sResourceDao().CreateK8sResourceInBatch(resourceList)
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 400, Err: fmt.Errorf("SyncK8sResource %v", err)}
|
||||
}
|
||||
return resourceList, nil
|
||||
}
|
||||
|
||||
//HandleResourceYaml -
|
||||
func (c *clusterAction) HandleResourceYaml(resourceYaml []byte, namespace string, change string, name string) []*model.BuildResource {
|
||||
var buildResourceList []*model.BuildResource
|
||||
var state int
|
||||
if change == "create" || change == "re-create" {
|
||||
state = model.CreateError
|
||||
} else if change == "update" {
|
||||
state = model.UpdateError
|
||||
}
|
||||
dc, err := dynamic.NewForConfig(c.config)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
resourceYamlByte := resourceYaml
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
decoder := yamlt.NewYAMLOrJSONDecoder(bytes.NewReader(resourceYamlByte), 1000)
|
||||
for {
|
||||
var rawObj runtime.RawExtension
|
||||
if err = decoder.Decode(&rawObj); err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
break
|
||||
}
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
obj, gvk, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
//转化成map
|
||||
unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
//转化成对象
|
||||
unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap}
|
||||
mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
buildResourceList = []*model.BuildResource{{
|
||||
State: state,
|
||||
ErrorOverview: err.Error(),
|
||||
}}
|
||||
return buildResourceList
|
||||
}
|
||||
var dri dynamic.ResourceInterface
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
|
||||
unstructuredObj.SetNamespace(namespace)
|
||||
dri = dc.Resource(mapping.Resource).Namespace(unstructuredObj.GetNamespace())
|
||||
} else {
|
||||
dri = dc.Resource(mapping.Resource)
|
||||
}
|
||||
br := &model.BuildResource{
|
||||
Resource: unstructuredObj,
|
||||
Dri: dri,
|
||||
}
|
||||
buildResourceList = append(buildResourceList, br)
|
||||
}
|
||||
for _, buildResource := range buildResourceList {
|
||||
unstructuredObj := buildResource.Resource
|
||||
switch change {
|
||||
case "re-create":
|
||||
unstructuredObj.SetResourceVersion("")
|
||||
unstructuredObj.SetCreationTimestamp(metav1.Time{})
|
||||
unstructuredObj.SetUID("")
|
||||
fallthrough
|
||||
case "create":
|
||||
obj, err := buildResource.Dri.Create(context.TODO(), unstructuredObj, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("k8s resource create error %v", err)
|
||||
buildResource.Resource = unstructuredObj
|
||||
buildResource.State = state
|
||||
buildResource.ErrorOverview = err.Error()
|
||||
} else {
|
||||
buildResource.Resource = obj
|
||||
buildResource.State = model.CreateSuccess
|
||||
buildResource.ErrorOverview = fmt.Sprintf("创建成功")
|
||||
}
|
||||
case "delete":
|
||||
err := buildResource.Dri.Delete(context.TODO(), name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("delete k8s resource error %v", err)
|
||||
}
|
||||
case "update":
|
||||
obj, err := buildResource.Dri.Update(context.TODO(), unstructuredObj, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("update k8s resource error %v", err)
|
||||
buildResource.Resource = unstructuredObj
|
||||
buildResource.State = state
|
||||
buildResource.ErrorOverview = err.Error()
|
||||
} else {
|
||||
buildResource.Resource = obj
|
||||
buildResource.State = model.UpdateSuccess
|
||||
buildResource.ErrorOverview = fmt.Sprintf("更新成功")
|
||||
}
|
||||
}
|
||||
}
|
||||
return buildResourceList
|
||||
}
|
428
api/handler/resource_import.go
Normal file
428
api/handler/resource_import.go
Normal file
@ -0,0 +1,428 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
rainbondutil "github.com/goodrain/rainbond/util"
|
||||
"github.com/goodrain/rainbond/util/constants"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/twinj/uuid"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//ResourceImport Import the converted k8s resources into recognition
|
||||
func (c *clusterAction) ResourceImport(namespace string, as map[string]model.ApplicationResource, eid string) (*model.ReturnResourceImport, *util.APIHandleError) {
|
||||
logrus.Infof("ResourceImport function begin")
|
||||
var returnResourceImport model.ReturnResourceImport
|
||||
err := db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
|
||||
tenant, err := c.createTenant(eid, namespace, tx)
|
||||
returnResourceImport.Tenant = tenant
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create tenant error:%v", err)}
|
||||
}
|
||||
for appName, components := range as {
|
||||
app, err := c.createApp(eid, tx, appName, tenant.UUID)
|
||||
if err != nil {
|
||||
logrus.Errorf("create app:%v err:%v", appName, err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create app:%v error:%v", appName, err)}
|
||||
}
|
||||
k8sResource, err := c.CreateK8sResource(tx, components.KubernetesResources, app.AppID)
|
||||
if err != nil {
|
||||
logrus.Errorf("create K8sResources err:%v", err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create K8sResources err:%v", err)}
|
||||
}
|
||||
var componentAttributes []model.ComponentAttributes
|
||||
for _, componentResource := range components.ConvertResource {
|
||||
component, err := c.CreateComponent(app, tenant.UUID, componentResource, namespace, false)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create app error:%v", err)}
|
||||
}
|
||||
c.createENV(componentResource.ENVManagement, component)
|
||||
c.createConfig(componentResource.ConfigManagement, component)
|
||||
c.createPort(componentResource.PortManagement, component)
|
||||
componentResource.TelescopicManagement.RuleID = c.createTelescopic(componentResource.TelescopicManagement, component)
|
||||
componentResource.HealthyCheckManagement.ProbeID = c.createHealthyCheck(componentResource.HealthyCheckManagement, component)
|
||||
c.createK8sAttributes(componentResource.ComponentK8sAttributesManagement, tenant.UUID, component)
|
||||
componentAttributes = append(componentAttributes, model.ComponentAttributes{
|
||||
TS: component,
|
||||
Image: componentResource.BasicManagement.Image,
|
||||
Cmd: componentResource.BasicManagement.Cmd,
|
||||
ENV: componentResource.ENVManagement,
|
||||
Config: componentResource.ConfigManagement,
|
||||
Port: componentResource.PortManagement,
|
||||
Telescopic: componentResource.TelescopicManagement,
|
||||
HealthyCheck: componentResource.HealthyCheckManagement,
|
||||
ComponentK8sAttributes: componentResource.ComponentK8sAttributesManagement,
|
||||
})
|
||||
}
|
||||
application := model.AppComponent{
|
||||
App: app,
|
||||
Component: componentAttributes,
|
||||
K8sResources: k8sResource,
|
||||
}
|
||||
returnResourceImport.App = append(returnResourceImport.App, application)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 400, Err: fmt.Errorf("resource import error:%v", err)}
|
||||
}
|
||||
logrus.Infof("ResourceImport function end")
|
||||
return &returnResourceImport, nil
|
||||
}
|
||||
|
||||
func (c *clusterAction) createTenant(eid string, namespace string, tx *gorm.DB) (*dbmodel.Tenants, error) {
|
||||
logrus.Infof("begin create tenant")
|
||||
var dbts dbmodel.Tenants
|
||||
id, name, errN := GetServiceManager().CreateTenandIDAndName(eid)
|
||||
if errN != nil {
|
||||
return nil, errN
|
||||
}
|
||||
dbts.EID = eid
|
||||
dbts.Namespace = namespace
|
||||
dbts.Name = name
|
||||
dbts.UUID = id
|
||||
dbts.LimitMemory = 0
|
||||
tenant, _ := db.GetManager().TenantDao().GetTenantIDByName(dbts.Name)
|
||||
if tenant != nil {
|
||||
logrus.Warningf("tenant %v already exists", dbts.Name)
|
||||
return tenant, nil
|
||||
}
|
||||
if err := db.GetManager().TenantDaoTransactions(tx).AddModel(&dbts); err != nil {
|
||||
if !strings.HasSuffix(err.Error(), "is exist") {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ns, err := c.clientset.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get namespace %v:%v", namespace, err)}
|
||||
}
|
||||
if ns.Labels == nil {
|
||||
ns.Labels = make(map[string]string)
|
||||
}
|
||||
ns.Labels[constants.ResourceManagedByLabel] = constants.Rainbond
|
||||
_, err = c.clientset.CoreV1().Namespaces().Update(context.Background(), ns, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to add label to namespace %v:%v", namespace, err)}
|
||||
}
|
||||
logrus.Infof("end create tenant")
|
||||
return &dbts, nil
|
||||
}
|
||||
|
||||
func (c *clusterAction) createApp(eid string, tx *gorm.DB, app string, tenantID string) (*dbmodel.Application, error) {
|
||||
appID := rainbondutil.NewUUID()
|
||||
application, _ := db.GetManager().ApplicationDaoTransactions(tx).GetAppByName(tenantID, app)
|
||||
if application != nil {
|
||||
logrus.Infof("app %v already exists", app)
|
||||
return application, nil
|
||||
}
|
||||
appReq := &dbmodel.Application{
|
||||
EID: eid,
|
||||
TenantID: tenantID,
|
||||
AppID: appID,
|
||||
AppName: app,
|
||||
AppType: "rainbond",
|
||||
GovernanceMode: dbmodel.GovernanceModeKubernetesNativeService,
|
||||
K8sApp: app,
|
||||
}
|
||||
if err := db.GetManager().ApplicationDaoTransactions(tx).AddModel(appReq); err != nil {
|
||||
return appReq, err
|
||||
}
|
||||
return appReq, nil
|
||||
}
|
||||
|
||||
func (c *clusterAction) CreateK8sResource(tx *gorm.DB, k8sResources []dbmodel.K8sResource, AppID string) ([]dbmodel.K8sResource, error) {
|
||||
var k8sResourceList []*dbmodel.K8sResource
|
||||
for _, k8sResource := range k8sResources {
|
||||
k8sResource.AppID = AppID
|
||||
kr := k8sResource
|
||||
k8sResourceList = append(k8sResourceList, &kr)
|
||||
}
|
||||
err := db.GetManager().K8sResourceDaoTransactions(tx).CreateK8sResourceInBatch(k8sResourceList)
|
||||
return k8sResources, err
|
||||
}
|
||||
|
||||
func (c *clusterAction) CreateComponent(app *dbmodel.Application, tenantID string, component model.ConvertResource, namespace string, isYaml bool) (*dbmodel.TenantServices, error) {
|
||||
var extendMethod string
|
||||
switch component.BasicManagement.ResourceType {
|
||||
case model.Deployment:
|
||||
extendMethod = string(dbmodel.ServiceTypeStatelessMultiple)
|
||||
case model.Job:
|
||||
extendMethod = string(dbmodel.ServiceTypeJob)
|
||||
case model.CronJob:
|
||||
extendMethod = string(dbmodel.ServiceTypeCronJob)
|
||||
case model.StateFulSet:
|
||||
extendMethod = string(dbmodel.ServiceTypeStateMultiple)
|
||||
}
|
||||
serviceID := rainbondutil.NewUUID()
|
||||
serviceAlias := "gr" + serviceID[len(serviceID)-6:]
|
||||
replicas := 1
|
||||
if component.BasicManagement.Replicas != nil {
|
||||
replicas = int(*component.BasicManagement.Replicas)
|
||||
}
|
||||
JobStrategy, err := json.Marshal(component.BasicManagement.JobStrategy)
|
||||
if err != nil {
|
||||
logrus.Errorf("component %v BasicManagement.JobStrategy json error%v", component.ComponentsName, err)
|
||||
}
|
||||
ts := dbmodel.TenantServices{
|
||||
TenantID: tenantID,
|
||||
ServiceID: serviceID,
|
||||
ServiceAlias: serviceAlias,
|
||||
ServiceName: serviceAlias,
|
||||
ServiceType: "application",
|
||||
Comment: "docker run application",
|
||||
ContainerCPU: int(component.BasicManagement.CPU),
|
||||
ContainerMemory: int(component.BasicManagement.Memory),
|
||||
ContainerGPU: 0,
|
||||
UpgradeMethod: "Rolling",
|
||||
ExtendMethod: extendMethod,
|
||||
Replicas: replicas,
|
||||
DeployVersion: time.Now().Format("20060102150405"),
|
||||
Category: "app_publish",
|
||||
CurStatus: "undeploy",
|
||||
Status: 0,
|
||||
Namespace: namespace,
|
||||
UpdateTime: time.Now(),
|
||||
Kind: "internal",
|
||||
AppID: app.AppID,
|
||||
K8sComponentName: component.ComponentsName,
|
||||
JobStrategy: string(JobStrategy),
|
||||
}
|
||||
if err := db.GetManager().TenantServiceDao().AddModel(&ts); err != nil {
|
||||
logrus.Errorf("add service error, %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if !isYaml {
|
||||
changeLabel := func(label map[string]string) map[string]string {
|
||||
label[constants.ResourceManagedByLabel] = constants.Rainbond
|
||||
label["service_id"] = serviceID
|
||||
label["version"] = ts.DeployVersion
|
||||
label["creater_id"] = string(rainbondutil.NewTimeVersion())
|
||||
label["migrator"] = "rainbond"
|
||||
label["creator"] = "Rainbond"
|
||||
return label
|
||||
}
|
||||
switch component.BasicManagement.ResourceType {
|
||||
case model.Deployment:
|
||||
dm, err := c.clientset.AppsV1().Deployments(namespace).Get(context.Background(), component.ComponentsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to get %v Deployments %v:%v", namespace, component.ComponentsName, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get Deployments %v:%v", namespace, err)}
|
||||
}
|
||||
if dm.Labels == nil {
|
||||
dm.Labels = make(map[string]string)
|
||||
}
|
||||
if dm.Spec.Template.Labels == nil {
|
||||
dm.Spec.Template.Labels = make(map[string]string)
|
||||
}
|
||||
dm.Labels = changeLabel(dm.Labels)
|
||||
dm.Spec.Template.Labels = changeLabel(dm.Spec.Template.Labels)
|
||||
_, err = c.clientset.AppsV1().Deployments(namespace).Update(context.Background(), dm, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to update Deployments %v:%v", namespace, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to update Deployments %v:%v", namespace, err)}
|
||||
}
|
||||
case model.Job:
|
||||
job, err := c.clientset.BatchV1().Jobs(namespace).Get(context.Background(), component.ComponentsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to get %v Jobs %v:%v", namespace, component.ComponentsName, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get Jobs %v:%v", namespace, err)}
|
||||
}
|
||||
if job.Labels == nil {
|
||||
job.Labels = make(map[string]string)
|
||||
}
|
||||
job.Labels = changeLabel(job.Labels)
|
||||
_, err = c.clientset.BatchV1().Jobs(namespace).Update(context.Background(), job, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to update StatefulSets %v:%v", namespace, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to update StatefulSets %v:%v", namespace, err)}
|
||||
}
|
||||
case model.CronJob:
|
||||
cr, err := c.clientset.BatchV1beta1().CronJobs(namespace).Get(context.Background(), component.ComponentsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to get %v CronJob %v:%v", namespace, component.ComponentsName, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get CronJob %v:%v", namespace, err)}
|
||||
}
|
||||
if cr.Labels == nil {
|
||||
cr.Labels = make(map[string]string)
|
||||
}
|
||||
cr.Labels = changeLabel(cr.Labels)
|
||||
if cr.Spec.JobTemplate.Labels == nil {
|
||||
cr.Spec.JobTemplate.Labels = make(map[string]string)
|
||||
}
|
||||
cr.Spec.JobTemplate.Labels = changeLabel(cr.Spec.JobTemplate.Labels)
|
||||
_, err = c.clientset.BatchV1beta1().CronJobs(namespace).Update(context.Background(), cr, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to update CronJobs %v:%v", namespace, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to update CronJobs %v:%v", namespace, err)}
|
||||
}
|
||||
case model.StateFulSet:
|
||||
sfs, err := c.clientset.AppsV1().StatefulSets(namespace).Get(context.Background(), component.ComponentsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to get %v StatefulSets %v:%v", namespace, component.ComponentsName, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to get StatefulSets %v:%v", namespace, err)}
|
||||
}
|
||||
if sfs.Labels == nil {
|
||||
sfs.Labels = make(map[string]string)
|
||||
}
|
||||
sfs.Labels = changeLabel(sfs.Labels)
|
||||
if sfs.Spec.Template.Labels == nil {
|
||||
sfs.Spec.Template.Labels = make(map[string]string)
|
||||
}
|
||||
sfs.Spec.Template.Labels = changeLabel(sfs.Spec.Template.Labels)
|
||||
_, err = c.clientset.AppsV1().StatefulSets(namespace).Update(context.Background(), sfs, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to update StatefulSets %v:%v", namespace, err)
|
||||
return nil, &util.APIHandleError{Code: 404, Err: fmt.Errorf("failed to update StatefulSets %v:%v", namespace, err)}
|
||||
}
|
||||
}
|
||||
}
|
||||
return &ts, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *clusterAction) createENV(envs []model.ENVManagement, service *dbmodel.TenantServices) {
|
||||
var envVar []*dbmodel.TenantServiceEnvVar
|
||||
for _, env := range envs {
|
||||
var envD dbmodel.TenantServiceEnvVar
|
||||
envD.AttrName = env.ENVKey
|
||||
envD.AttrValue = env.ENVValue
|
||||
envD.TenantID = service.TenantID
|
||||
envD.ServiceID = service.ServiceID
|
||||
envD.ContainerPort = 0
|
||||
envD.IsChange = true
|
||||
envD.Name = env.ENVExplain
|
||||
envD.Scope = "inner"
|
||||
envVar = append(envVar, &envD)
|
||||
}
|
||||
if err := db.GetManager().TenantServiceEnvVarDao().CreateOrUpdateEnvsInBatch(envVar); err != nil {
|
||||
logrus.Errorf("%v Environment variable creation failed:%v", service.ServiceAlias, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clusterAction) createConfig(configs []model.ConfigManagement, service *dbmodel.TenantServices) {
|
||||
var configVar []*dbmodel.TenantServiceVolume
|
||||
for _, config := range configs {
|
||||
tsv := &dbmodel.TenantServiceVolume{
|
||||
ServiceID: service.ServiceID,
|
||||
VolumeName: config.ConfigName,
|
||||
VolumePath: config.ConfigPath,
|
||||
VolumeType: "config-file",
|
||||
Category: "",
|
||||
VolumeProviderName: "",
|
||||
IsReadOnly: false,
|
||||
VolumeCapacity: 0,
|
||||
AccessMode: "RWX",
|
||||
SharePolicy: "exclusive",
|
||||
BackupPolicy: "exclusive",
|
||||
ReclaimPolicy: "exclusive",
|
||||
AllowExpansion: false,
|
||||
Mode: &config.Mode,
|
||||
}
|
||||
configVar = append(configVar, tsv)
|
||||
}
|
||||
err := db.GetManager().TenantServiceVolumeDao().CreateOrUpdateVolumesInBatch(configVar)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v configuration file creation failed:%v", service.ServiceAlias, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clusterAction) createPort(ports []model.PortManagement, service *dbmodel.TenantServices) {
|
||||
var portVar []*dbmodel.TenantServicesPort
|
||||
for _, port := range ports {
|
||||
portAlias := strings.Replace(service.ServiceAlias, "-", "_", -1)
|
||||
var vpD dbmodel.TenantServicesPort
|
||||
vpD.ServiceID = service.ServiceID
|
||||
vpD.TenantID = service.TenantID
|
||||
vpD.IsInnerService = &port.Inner
|
||||
vpD.IsOuterService = &port.Outer
|
||||
vpD.ContainerPort = int(port.Port)
|
||||
vpD.MappingPort = int(port.Port)
|
||||
vpD.Protocol = port.Protocol
|
||||
vpD.PortAlias = fmt.Sprintf("%v%v", strings.ToUpper(portAlias), port.Port)
|
||||
vpD.K8sServiceName = fmt.Sprintf("%v-%v", service.ServiceAlias, port.Port)
|
||||
portVar = append(portVar, &vpD)
|
||||
}
|
||||
if err := db.GetManager().TenantServicesPortDao().CreateOrUpdatePortsInBatch(portVar); err != nil {
|
||||
logrus.Errorf("%v port creation failed:%v", service.ServiceAlias, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clusterAction) createTelescopic(telescopic model.TelescopicManagement, service *dbmodel.TenantServices) string {
|
||||
if !telescopic.Enable {
|
||||
return ""
|
||||
}
|
||||
r := &dbmodel.TenantServiceAutoscalerRules{
|
||||
RuleID: rainbondutil.NewUUID(),
|
||||
ServiceID: service.ServiceID,
|
||||
Enable: true,
|
||||
XPAType: "hpa",
|
||||
MinReplicas: int(telescopic.MinReplicas),
|
||||
MaxReplicas: int(telescopic.MaxReplicas),
|
||||
}
|
||||
telescopic.RuleID = r.RuleID
|
||||
if err := db.GetManager().TenantServceAutoscalerRulesDao().AddModel(r); err != nil {
|
||||
logrus.Errorf("%v TenantServiceAutoscalerRules creation failed:%v", service.ServiceAlias, err)
|
||||
return ""
|
||||
}
|
||||
for _, metric := range telescopic.CPUOrMemory {
|
||||
m := &dbmodel.TenantServiceAutoscalerRuleMetrics{
|
||||
RuleID: r.RuleID,
|
||||
MetricsType: metric.MetricsType,
|
||||
MetricsName: metric.MetricsName,
|
||||
MetricTargetType: metric.MetricTargetType,
|
||||
MetricTargetValue: metric.MetricTargetValue,
|
||||
}
|
||||
if err := db.GetManager().TenantServceAutoscalerRuleMetricsDao().AddModel(m); err != nil {
|
||||
logrus.Errorf("%v TenantServceAutoscalerRuleMetricsDao creation failed:%v", service.ServiceAlias, err)
|
||||
}
|
||||
}
|
||||
return r.RuleID
|
||||
}
|
||||
|
||||
func (c *clusterAction) createHealthyCheck(telescopic model.HealthyCheckManagement, service *dbmodel.TenantServices) string {
|
||||
if telescopic.Status == 0 {
|
||||
return ""
|
||||
}
|
||||
var tspD dbmodel.TenantServiceProbe
|
||||
tspD.ServiceID = service.ServiceID
|
||||
tspD.Cmd = telescopic.Command
|
||||
tspD.FailureThreshold = telescopic.FailureThreshold
|
||||
tspD.HTTPHeader = telescopic.HTTPHeader
|
||||
tspD.InitialDelaySecond = telescopic.InitialDelaySecond
|
||||
tspD.IsUsed = &telescopic.Status
|
||||
tspD.Mode = telescopic.Mode
|
||||
tspD.Path = telescopic.Path
|
||||
tspD.PeriodSecond = telescopic.PeriodSecond
|
||||
tspD.Port = telescopic.Port
|
||||
tspD.ProbeID = strings.Replace(uuid.NewV4().String(), "-", "", -1)
|
||||
tspD.Scheme = telescopic.DetectionMethod
|
||||
tspD.SuccessThreshold = telescopic.SuccessThreshold
|
||||
tspD.TimeoutSecond = telescopic.TimeoutSecond
|
||||
tspD.FailureAction = ""
|
||||
if err := GetServiceManager().ServiceProbe(&tspD, "add"); err != nil {
|
||||
logrus.Errorf("%v createHealthyCheck creation failed:%v", service.ServiceAlias, err)
|
||||
}
|
||||
return tspD.ProbeID
|
||||
}
|
||||
|
||||
func (c *clusterAction) createK8sAttributes(specials []*dbmodel.ComponentK8sAttributes, tenantID string, component *dbmodel.TenantServices) {
|
||||
for _, specials := range specials {
|
||||
specials.TenantID = tenantID
|
||||
specials.ComponentID = component.ServiceID
|
||||
}
|
||||
err := db.GetManager().ComponentK8sAttributeDao().CreateOrUpdateAttributesInBatch(specials)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v createSpecial creation failed:%v", component.ServiceAlias, err)
|
||||
}
|
||||
}
|
417
api/handler/resource_public_function.go
Normal file
417
api/handler/resource_public_function.go
Normal file
@ -0,0 +1,417 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/api/model"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"path"
|
||||
"sigs.k8s.io/yaml"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (c *clusterAction) PodTemplateSpecResource(parameter model.YamlResourceParameter) {
|
||||
//Port
|
||||
var ps []model.PortManagement
|
||||
for _, port := range parameter.Template.Spec.Containers[0].Ports {
|
||||
if string(port.Protocol) == "UDP" {
|
||||
ps = append(ps, model.PortManagement{
|
||||
Port: port.ContainerPort,
|
||||
Protocol: "UDP",
|
||||
Inner: false,
|
||||
Outer: false,
|
||||
})
|
||||
} else {
|
||||
ps = append(ps, model.PortManagement{
|
||||
Port: port.ContainerPort,
|
||||
Protocol: "TCP",
|
||||
Inner: false,
|
||||
Outer: false,
|
||||
})
|
||||
}
|
||||
logrus.Warningf("Transport protocol type not recognized%v", port.Protocol)
|
||||
}
|
||||
|
||||
//ENV
|
||||
var envs []model.ENVManagement
|
||||
for i := 0; i < len(parameter.Template.Spec.Containers[0].Env); i++ {
|
||||
if cm := parameter.Template.Spec.Containers[0].Env[i].ValueFrom; cm == nil {
|
||||
envs = append(envs, model.ENVManagement{
|
||||
ENVKey: parameter.Template.Spec.Containers[0].Env[i].Name,
|
||||
ENVValue: parameter.Template.Spec.Containers[0].Env[i].Value,
|
||||
ENVExplain: "",
|
||||
})
|
||||
parameter.Template.Spec.Containers[0].Env = append(parameter.Template.Spec.Containers[0].Env[:i], parameter.Template.Spec.Containers[0].Env[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
//Configs
|
||||
var configs []model.ConfigManagement
|
||||
//这一块是处理配置文件
|
||||
//配置文件的名字最终都是configmap里面的key值。
|
||||
//volume在被挂载后存在四种情况
|
||||
//第一种是volume存在items,volumeMount的SubPath不等于空。路径直接是volumeMount里面的mountPath。
|
||||
//第二种是volume存在items,volumeMount的SubPath等于空。路径则变成volumeMount里面的mountPath拼接上items里面每一个元素的key值。
|
||||
//第三种是volume不存在items,volumeMount的SubPath不等于空。路径直接是volumeMount里面的mountPath。
|
||||
//第四种是volume不存在items,volumeMount的SubPath等于空。路径则变成volumeMount里面的mountPath拼接上configmap资源里面每一个元素的key值
|
||||
cmMap := make(map[string]corev1.ConfigMap)
|
||||
cmList, err := c.clientset.CoreV1().ConfigMaps(parameter.Namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get ConfigMap%v", err)
|
||||
}
|
||||
for _, cm := range cmList.Items {
|
||||
cmMap[cm.Name] = cm
|
||||
}
|
||||
cmList.Items = append(cmList.Items, parameter.CMs...)
|
||||
for _, volume := range parameter.Template.Spec.Volumes {
|
||||
if volume.ConfigMap != nil && err == nil {
|
||||
cm, _ := cmMap[volume.ConfigMap.Name]
|
||||
cmData := cm.Data
|
||||
isLog := true
|
||||
var index int
|
||||
for i, volumeMount := range parameter.Template.Spec.Containers[0].VolumeMounts {
|
||||
if volume.Name != volumeMount.Name {
|
||||
continue
|
||||
}
|
||||
isLog = false
|
||||
index = i
|
||||
if volume.ConfigMap.Items != nil {
|
||||
if volumeMount.SubPath != "" {
|
||||
configName := ""
|
||||
var mode int32
|
||||
for _, item := range volume.ConfigMap.Items {
|
||||
if item.Path == volumeMount.SubPath {
|
||||
configName = item.Key
|
||||
mode = *item.Mode
|
||||
}
|
||||
}
|
||||
configs = append(configs, model.ConfigManagement{
|
||||
ConfigName: configName,
|
||||
ConfigPath: volumeMount.MountPath,
|
||||
ConfigValue: cmData[configName],
|
||||
Mode: mode,
|
||||
})
|
||||
continue
|
||||
}
|
||||
p := volumeMount.MountPath
|
||||
for _, item := range volume.ConfigMap.Items {
|
||||
p := path.Join(p, item.Path)
|
||||
var mode int32
|
||||
if item.Mode != nil {
|
||||
mode = *item.Mode
|
||||
}
|
||||
configs = append(configs, model.ConfigManagement{
|
||||
ConfigName: item.Key,
|
||||
ConfigPath: p,
|
||||
ConfigValue: cmData[item.Key],
|
||||
Mode: mode,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
mode := int32(777)
|
||||
if volume.ConfigMap.DefaultMode != nil {
|
||||
mode = *volume.ConfigMap.DefaultMode
|
||||
}
|
||||
if volumeMount.SubPath != "" {
|
||||
configs = append(configs, model.ConfigManagement{
|
||||
ConfigName: volumeMount.SubPath,
|
||||
ConfigPath: volumeMount.MountPath,
|
||||
ConfigValue: cmData[volumeMount.SubPath],
|
||||
Mode: mode,
|
||||
})
|
||||
continue
|
||||
}
|
||||
mountPath := volumeMount.MountPath
|
||||
for key, val := range cmData {
|
||||
mountPath = path.Join(mountPath, key)
|
||||
configs = append(configs, model.ConfigManagement{
|
||||
ConfigName: key,
|
||||
ConfigPath: mountPath,
|
||||
ConfigValue: val,
|
||||
Mode: *volume.ConfigMap.DefaultMode,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if isLog {
|
||||
logrus.Warningf("configmap type resource %v is not mounted in volumemount", volume.ConfigMap.Name)
|
||||
continue
|
||||
}
|
||||
parameter.Template.Spec.Containers[0].VolumeMounts = append(parameter.Template.Spec.Containers[0].VolumeMounts[:index], parameter.Template.Spec.Containers[0].VolumeMounts[index+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
//TelescopicManagement
|
||||
HPAList, err := c.clientset.AutoscalingV1().HorizontalPodAutoscalers(parameter.Namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get HorizontalPodAutoscalers list:%v", err)
|
||||
}
|
||||
HPAList.Items = append(HPAList.Items, parameter.HPAs...)
|
||||
var t model.TelescopicManagement
|
||||
//这一块就是自动伸缩的对应解析,
|
||||
//需要注意的一点是hpa的cpu和memory的阈值设置是通过Annotations["autoscaling.alpha.kubernetes.io/metrics"]字段设置
|
||||
//而且它的返回值是个json字符串所以设置了一个结构体进行解析。
|
||||
for _, hpa := range HPAList.Items {
|
||||
if (hpa.Spec.ScaleTargetRef.Kind != model.Deployment && hpa.Spec.ScaleTargetRef.Kind != model.StateFulSet) || hpa.Spec.ScaleTargetRef.Name != parameter.Name {
|
||||
t.Enable = false
|
||||
continue
|
||||
}
|
||||
t.Enable = true
|
||||
t.MinReplicas = *hpa.Spec.MinReplicas
|
||||
t.MaxReplicas = hpa.Spec.MaxReplicas
|
||||
var cpuormemorys []*dbmodel.TenantServiceAutoscalerRuleMetrics
|
||||
cpuUsage := hpa.Spec.TargetCPUUtilizationPercentage
|
||||
if cpuUsage != nil {
|
||||
cpuormemorys = append(cpuormemorys, &dbmodel.TenantServiceAutoscalerRuleMetrics{
|
||||
MetricsType: "resource_metrics",
|
||||
MetricsName: "cpu",
|
||||
MetricTargetType: "utilization",
|
||||
MetricTargetValue: int(*cpuUsage),
|
||||
})
|
||||
}
|
||||
CPUAndMemoryJSON, ok := hpa.Annotations["autoscaling.alpha.kubernetes.io/metrics"]
|
||||
if ok {
|
||||
type com struct {
|
||||
T string `json:"type"`
|
||||
Resource map[string]interface{}
|
||||
}
|
||||
var c []com
|
||||
err := json.Unmarshal([]byte(CPUAndMemoryJSON), &c)
|
||||
if err != nil {
|
||||
logrus.Errorf("autoscaling.alpha.kubernetes.io/metrics parsing failed:%v", err)
|
||||
}
|
||||
|
||||
for _, cpuormemory := range c {
|
||||
switch cpuormemory.Resource["name"] {
|
||||
case "cpu":
|
||||
cpu := fmt.Sprint(cpuormemory.Resource["targetAverageValue"])
|
||||
cpuUnit := cpu[len(cpu)-1:]
|
||||
var cpuUsage int
|
||||
if cpuUnit == "m" {
|
||||
cpuUsage, _ = strconv.Atoi(cpu[:len(cpu)-1])
|
||||
}
|
||||
if cpuUnit == "g" || cpuUnit == "G" {
|
||||
cpuUsage, _ = strconv.Atoi(cpu[:len(cpu)-1])
|
||||
cpuUsage = cpuUsage * 1024
|
||||
}
|
||||
cpuormemorys = append(cpuormemorys, &dbmodel.TenantServiceAutoscalerRuleMetrics{
|
||||
MetricsType: "resource_metrics",
|
||||
MetricsName: "cpu",
|
||||
MetricTargetType: "average_value",
|
||||
MetricTargetValue: cpuUsage,
|
||||
})
|
||||
case "memory":
|
||||
memory := fmt.Sprint(cpuormemory.Resource["targetAverageValue"])
|
||||
memoryUnit := memory[:len(memory)-1]
|
||||
var MemoryUsage int
|
||||
if memoryUnit == "m" {
|
||||
MemoryUsage, _ = strconv.Atoi(memory[:len(memory)-1])
|
||||
}
|
||||
if memoryUnit == "g" || memoryUnit == "G" {
|
||||
MemoryUsage, _ = strconv.Atoi(memory[:len(memory)-1])
|
||||
MemoryUsage = MemoryUsage * 1024
|
||||
}
|
||||
cpuormemorys = append(cpuormemorys, &dbmodel.TenantServiceAutoscalerRuleMetrics{
|
||||
MetricsType: "resource_metrics",
|
||||
MetricsName: "cpu",
|
||||
MetricTargetType: "average_value",
|
||||
MetricTargetValue: MemoryUsage,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
t.CPUOrMemory = cpuormemorys
|
||||
}
|
||||
|
||||
//HealthyCheckManagement
|
||||
var hcm model.HealthyCheckManagement
|
||||
livenessProbe := parameter.Template.Spec.Containers[0].LivenessProbe
|
||||
if livenessProbe != nil {
|
||||
var httpHeaders []string
|
||||
if livenessProbe.HTTPGet != nil {
|
||||
for _, httpHeader := range livenessProbe.HTTPGet.HTTPHeaders {
|
||||
nv := httpHeader.Name + "=" + httpHeader.Value
|
||||
httpHeaders = append(httpHeaders, nv)
|
||||
}
|
||||
hcm.DetectionMethod = strings.ToLower(string(livenessProbe.HTTPGet.Scheme))
|
||||
hcm.Path = livenessProbe.HTTPGet.Path
|
||||
hcm.Port = int(livenessProbe.HTTPGet.Port.IntVal)
|
||||
}
|
||||
hcm.Status = 1
|
||||
if livenessProbe.Exec != nil {
|
||||
hcm.Command = strings.Join(livenessProbe.Exec.Command, " ")
|
||||
}
|
||||
hcm.HTTPHeader = strings.Join(httpHeaders, ",")
|
||||
hcm.Mode = "liveness"
|
||||
hcm.InitialDelaySecond = int(livenessProbe.InitialDelaySeconds)
|
||||
hcm.PeriodSecond = int(livenessProbe.PeriodSeconds)
|
||||
hcm.TimeoutSecond = int(livenessProbe.TimeoutSeconds)
|
||||
hcm.FailureThreshold = int(livenessProbe.FailureThreshold)
|
||||
hcm.SuccessThreshold = int(livenessProbe.SuccessThreshold)
|
||||
} else {
|
||||
readinessProbe := parameter.Template.Spec.Containers[0].ReadinessProbe
|
||||
if readinessProbe != nil {
|
||||
var httpHeaders []string
|
||||
if readinessProbe.HTTPGet != nil {
|
||||
for _, httpHeader := range readinessProbe.HTTPGet.HTTPHeaders {
|
||||
nv := httpHeader.Name + "=" + httpHeader.Value
|
||||
httpHeaders = append(httpHeaders, nv)
|
||||
}
|
||||
hcm.DetectionMethod = strings.ToLower(string(readinessProbe.HTTPGet.Scheme))
|
||||
hcm.Path = readinessProbe.HTTPGet.Path
|
||||
hcm.Port = int(readinessProbe.HTTPGet.Port.IntVal)
|
||||
}
|
||||
hcm.Status = 1
|
||||
hcm.Mode = "readiness"
|
||||
if readinessProbe.Exec != nil {
|
||||
hcm.Command = strings.Join(readinessProbe.Exec.Command, " ")
|
||||
}
|
||||
hcm.HTTPHeader = strings.Join(httpHeaders, ",")
|
||||
hcm.InitialDelaySecond = int(readinessProbe.InitialDelaySeconds)
|
||||
hcm.PeriodSecond = int(readinessProbe.PeriodSeconds)
|
||||
hcm.TimeoutSecond = int(readinessProbe.TimeoutSeconds)
|
||||
hcm.FailureThreshold = int(readinessProbe.FailureThreshold)
|
||||
hcm.SuccessThreshold = int(readinessProbe.SuccessThreshold)
|
||||
}
|
||||
}
|
||||
|
||||
var attributes []*dbmodel.ComponentK8sAttributes
|
||||
if parameter.Template.Spec.Containers[0].Env != nil && len(parameter.Template.Spec.Containers[0].Env) > 0 {
|
||||
envYaml, err := ObjectToJSONORYaml("yaml", parameter.Template.Spec.Containers[0].Env)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v env %v", parameter.Name, err)
|
||||
}
|
||||
envAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameENV,
|
||||
SaveType: "yaml",
|
||||
AttributeValue: envYaml,
|
||||
}
|
||||
attributes = append(attributes, envAttributes)
|
||||
}
|
||||
if parameter.Template.Spec.Volumes != nil {
|
||||
volumesYaml, err := ObjectToJSONORYaml("yaml", parameter.Template.Spec.Volumes)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v volumes %v", parameter.Name, err)
|
||||
}
|
||||
volumesAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameVolumes,
|
||||
SaveType: "yaml",
|
||||
AttributeValue: volumesYaml,
|
||||
}
|
||||
attributes = append(attributes, volumesAttributes)
|
||||
|
||||
}
|
||||
if parameter.Template.Spec.Containers[0].VolumeMounts != nil {
|
||||
volumeMountsYaml, err := ObjectToJSONORYaml("yaml", parameter.Template.Spec.Containers[0].VolumeMounts)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v volumeMounts %v", parameter.Name, err)
|
||||
}
|
||||
volumeMountsAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameVolumeMounts,
|
||||
SaveType: "yaml",
|
||||
AttributeValue: volumeMountsYaml,
|
||||
}
|
||||
attributes = append(attributes, volumeMountsAttributes)
|
||||
}
|
||||
if parameter.Template.Spec.ServiceAccountName != "" {
|
||||
serviceAccountAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameServiceAccountName,
|
||||
SaveType: "string",
|
||||
AttributeValue: parameter.Template.Spec.ServiceAccountName,
|
||||
}
|
||||
attributes = append(attributes, serviceAccountAttributes)
|
||||
}
|
||||
if parameter.RsLabel != nil {
|
||||
labelsJSON, err := ObjectToJSONORYaml("json", parameter.RsLabel)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v labels %v", parameter.Name, err)
|
||||
}
|
||||
labelsAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameLabels,
|
||||
SaveType: "json",
|
||||
AttributeValue: labelsJSON,
|
||||
}
|
||||
attributes = append(attributes, labelsAttributes)
|
||||
}
|
||||
|
||||
if parameter.Template.Spec.NodeSelector != nil {
|
||||
NodeSelectorJSON, err := ObjectToJSONORYaml("json", parameter.Template.Spec.NodeSelector)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v nodeSelector %v", parameter.Name, err)
|
||||
}
|
||||
nodeSelectorAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameNodeSelector,
|
||||
SaveType: "json",
|
||||
AttributeValue: NodeSelectorJSON,
|
||||
}
|
||||
attributes = append(attributes, nodeSelectorAttributes)
|
||||
}
|
||||
if parameter.Template.Spec.Tolerations != nil {
|
||||
tolerationsYaml, err := ObjectToJSONORYaml("yaml", parameter.Template.Spec.Tolerations)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v tolerations %v", parameter.Name, err)
|
||||
}
|
||||
tolerationsAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameTolerations,
|
||||
SaveType: "yaml",
|
||||
AttributeValue: tolerationsYaml,
|
||||
}
|
||||
attributes = append(attributes, tolerationsAttributes)
|
||||
}
|
||||
if parameter.Template.Spec.Affinity != nil {
|
||||
affinityYaml, err := ObjectToJSONORYaml("yaml", parameter.Template.Spec.Affinity)
|
||||
if err != nil {
|
||||
logrus.Errorf("deployment:%v affinity %v", parameter.Name, err)
|
||||
}
|
||||
affinityAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNameAffinity,
|
||||
SaveType: "yaml",
|
||||
AttributeValue: affinityYaml,
|
||||
}
|
||||
attributes = append(attributes, affinityAttributes)
|
||||
}
|
||||
if securityContext := parameter.Template.Spec.Containers[0].SecurityContext; securityContext != nil && securityContext.Privileged != nil {
|
||||
privilegedAttributes := &dbmodel.ComponentK8sAttributes{
|
||||
Name: dbmodel.K8sAttributeNamePrivileged,
|
||||
SaveType: "string",
|
||||
AttributeValue: strconv.FormatBool(*securityContext.Privileged),
|
||||
}
|
||||
attributes = append(attributes, privilegedAttributes)
|
||||
}
|
||||
|
||||
*parameter.ComponentsCR = append(*parameter.ComponentsCR, model.ConvertResource{
|
||||
ComponentsName: parameter.Name,
|
||||
BasicManagement: parameter.Basic,
|
||||
PortManagement: ps,
|
||||
ENVManagement: envs,
|
||||
ConfigManagement: configs,
|
||||
TelescopicManagement: t,
|
||||
HealthyCheckManagement: hcm,
|
||||
ComponentK8sAttributesManagement: attributes,
|
||||
})
|
||||
}
|
||||
|
||||
//ObjectToJSONORYaml changeType true is json / yaml
|
||||
func ObjectToJSONORYaml(changeType string, data interface{}) (string, error) {
|
||||
if data == nil {
|
||||
return "", nil
|
||||
}
|
||||
dataJSON, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("json serialization failed err:%v", err)
|
||||
}
|
||||
if changeType == "json" {
|
||||
return string(dataJSON), nil
|
||||
}
|
||||
dataYaml, err := yaml.JSONToYAML(dataJSON)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("yaml serialization failed err:%v", err)
|
||||
}
|
||||
return string(dataYaml), nil
|
||||
}
|
@ -937,6 +937,9 @@ func (s *ServiceAction) ServiceUpdate(sc map[string]interface{}) error {
|
||||
ts.ExtendMethod = extendMethod
|
||||
ts.ServiceType = extendMethod
|
||||
}
|
||||
if js, ok := sc["job_strategy"].(string); ok {
|
||||
ts.JobStrategy = js
|
||||
}
|
||||
//update component
|
||||
if err := db.GetManager().TenantServiceDao().UpdateModel(ts); err != nil {
|
||||
logrus.Errorf("update service error, %v", err)
|
||||
@ -2914,6 +2917,28 @@ func (s *ServiceAction) SyncComponentEndpoints(tx *gorm.DB, components []*api_mo
|
||||
return db.GetManager().ThirdPartySvcDiscoveryCfgDaoTransactions(tx).CreateOrUpdate3rdSvcDiscoveryCfgInBatch(thirdPartySvcDiscoveryCfgs)
|
||||
}
|
||||
|
||||
// SyncComponentK8sAttributes -
|
||||
func (s *ServiceAction) SyncComponentK8sAttributes(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error {
|
||||
var (
|
||||
componentIDs []string
|
||||
k8sAttributes []*dbmodel.ComponentK8sAttributes
|
||||
)
|
||||
for _, component := range components {
|
||||
if component.ComponentK8sAttributes == nil || len(component.ComponentK8sAttributes) == 0 {
|
||||
continue
|
||||
}
|
||||
componentIDs = append(componentIDs, component.ComponentBase.ComponentID)
|
||||
for _, k8sAttribute := range component.ComponentK8sAttributes {
|
||||
k8sAttributes = append(k8sAttributes, k8sAttribute.DbModel(app.TenantID, component.ComponentBase.ComponentID))
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.GetManager().ComponentK8sAttributeDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
return db.GetManager().ComponentK8sAttributeDaoTransactions(tx).CreateOrUpdateAttributesInBatch(k8sAttributes)
|
||||
}
|
||||
|
||||
// Log returns the logs reader for a container in a pod, a pod or a component.
|
||||
func (s *ServiceAction) Log(w http.ResponseWriter, r *http.Request, component *dbmodel.TenantServices, podName, containerName string, follow bool) error {
|
||||
// If podName and containerName is missing, return the logs reader for the component
|
||||
@ -2985,6 +3010,8 @@ func TransStatus(eStatus string) string {
|
||||
return "未部署"
|
||||
case "deployed":
|
||||
return "已部署"
|
||||
case "succeeded":
|
||||
return "已完成"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -90,6 +90,10 @@ type ServiceHandler interface {
|
||||
DeleteServiceMonitor(tenantID, serviceID, name string) (*dbmodel.TenantServiceMonitor, error)
|
||||
AddServiceMonitor(tenantID, serviceID string, add api_model.AddServiceMonitorRequestStruct) (*dbmodel.TenantServiceMonitor, error)
|
||||
|
||||
CreateK8sAttribute(tenantID, componentID string, k8sAttr *api_model.ComponentK8sAttribute) error
|
||||
UpdateK8sAttribute(componentID string, k8sAttributes *api_model.ComponentK8sAttribute) error
|
||||
DeleteK8sAttribute(componentID, name string) error
|
||||
|
||||
SyncComponentBase(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error
|
||||
SyncComponentMonitors(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error
|
||||
SyncComponentPorts(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error
|
||||
@ -103,6 +107,7 @@ type ServiceHandler interface {
|
||||
SyncComponentPlugins(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error
|
||||
SyncComponentScaleRules(tx *gorm.DB, components []*api_model.Component) error
|
||||
SyncComponentEndpoints(tx *gorm.DB, components []*api_model.Component) error
|
||||
SyncComponentK8sAttributes(tx *gorm.DB, app *dbmodel.Application, components []*api_model.Component) error
|
||||
|
||||
Log(w http.ResponseWriter, r *http.Request, component *dbmodel.TenantServices, podName, containerName string, follow bool) error
|
||||
}
|
||||
|
@ -319,6 +319,7 @@ func (o *OperationHandler) buildFromImage(r *model.ComponentBuildReq, service *d
|
||||
|
||||
func (o *OperationHandler) buildFromSourceCode(r *model.ComponentBuildReq, service *dbmodel.TenantServices) error {
|
||||
if r.CodeInfo.RepoURL == "" || r.CodeInfo.Branch == "" || r.DeployVersion == "" {
|
||||
logrus.Infof("r.CodeInfo.RepoURL:%v, r.CodeInfo.Branch:%v, r.DeployVersion:%v", r.CodeInfo.RepoURL, r.CodeInfo.Branch, r.DeployVersion)
|
||||
return fmt.Errorf("build from code failure, args error")
|
||||
}
|
||||
body := make(map[string]interface{})
|
||||
|
422
api/handler/yaml_resource.go
Normal file
422
api/handler/yaml_resource.go
Normal file
@ -0,0 +1,422 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
api_model "github.com/goodrain/rainbond/api/model"
|
||||
"github.com/goodrain/rainbond/api/util"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
appv1 "k8s.io/api/apps/v1"
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
yamlt "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//AppYamlResourceName -
|
||||
func (c *clusterAction) AppYamlResourceName(yamlResource api_model.YamlResource) (map[string]api_model.LabelResource, *util.APIHandleError) {
|
||||
logrus.Infof("AppYamlResourceName begin")
|
||||
fileResource := make(map[string]api_model.LabelResource)
|
||||
k8sResourceObjects := c.YamlToResource(yamlResource)
|
||||
var DeployNames, JobNames, CJNames, SFSNames, RoleNames, HPANames, RBNames, SANames, SecretNames, ServiceNames, CMNames, NetworkPolicyNames, IngressNames, PVCNames []string
|
||||
defaultResource := make(map[string][]string)
|
||||
for _, k8sResourceObject := range k8sResourceObjects {
|
||||
if k8sResourceObject.Error != "" {
|
||||
fileResource[k8sResourceObject.FileName] = api_model.LabelResource{
|
||||
Status: k8sResourceObject.Error,
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, buildResource := range k8sResourceObject.BuildResources {
|
||||
switch buildResource.Resource.GetKind() {
|
||||
case api_model.Deployment:
|
||||
DeployNames = append(DeployNames, buildResource.Resource.GetName())
|
||||
case api_model.Job:
|
||||
JobNames = append(JobNames, buildResource.Resource.GetName())
|
||||
case api_model.CronJob:
|
||||
CJNames = append(CJNames, buildResource.Resource.GetName())
|
||||
case api_model.StateFulSet:
|
||||
SFSNames = append(SFSNames, buildResource.Resource.GetName())
|
||||
case api_model.Role:
|
||||
RoleNames = append(RoleNames, buildResource.Resource.GetName())
|
||||
case api_model.HorizontalPodAutoscaler:
|
||||
HPANames = append(HPANames, buildResource.Resource.GetName())
|
||||
case api_model.RoleBinding:
|
||||
RBNames = append(RBNames, buildResource.Resource.GetName())
|
||||
case api_model.ServiceAccount:
|
||||
SANames = append(SANames, buildResource.Resource.GetName())
|
||||
case api_model.Secret:
|
||||
SecretNames = append(SecretNames, buildResource.Resource.GetName())
|
||||
case api_model.Service:
|
||||
ServiceNames = append(ServiceNames, buildResource.Resource.GetName())
|
||||
case api_model.ConfigMap:
|
||||
CMNames = append(CMNames, buildResource.Resource.GetName())
|
||||
case api_model.NetworkPolicy:
|
||||
NetworkPolicyNames = append(NetworkPolicyNames, buildResource.Resource.GetName())
|
||||
case api_model.Ingress:
|
||||
IngressNames = append(IngressNames, buildResource.Resource.GetName())
|
||||
case api_model.PVC:
|
||||
PVCNames = append(PVCNames, buildResource.Resource.GetName())
|
||||
default:
|
||||
defaultNames, ok := defaultResource[buildResource.Resource.GetKind()]
|
||||
if ok {
|
||||
defaultResource[buildResource.Resource.GetKind()] = append(defaultNames, buildResource.Resource.GetName())
|
||||
} else {
|
||||
defaultResource[buildResource.Resource.GetKind()] = []string{buildResource.Resource.GetName()}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fileResource["app_resource"] = api_model.LabelResource{
|
||||
UnSupport: defaultResource,
|
||||
Workloads: api_model.WorkLoadsResource{
|
||||
Deployments: DeployNames,
|
||||
Jobs: JobNames,
|
||||
CronJobs: CJNames,
|
||||
StateFulSets: SFSNames,
|
||||
},
|
||||
Others: api_model.OtherResource{
|
||||
Services: ServiceNames,
|
||||
PVC: PVCNames,
|
||||
Ingresses: IngressNames,
|
||||
NetworkPolicies: NetworkPolicyNames,
|
||||
ConfigMaps: CMNames,
|
||||
Secrets: SecretNames,
|
||||
ServiceAccounts: ServiceNames,
|
||||
RoleBindings: RoleNames,
|
||||
HorizontalPodAutoscalers: HPANames,
|
||||
Roles: RoleNames,
|
||||
},
|
||||
Status: "",
|
||||
}
|
||||
logrus.Infof("AppYamlResourceName end")
|
||||
return fileResource, nil
|
||||
}
|
||||
|
||||
//AppYamlResourceDetailed -
|
||||
func (c *clusterAction) AppYamlResourceDetailed(yamlResource api_model.YamlResource, yamlImport bool) (api_model.ApplicationResource, *util.APIHandleError) {
|
||||
logrus.Infof("AppYamlResourceDetailed begin")
|
||||
k8sResourceObjects := c.YamlToResource(yamlResource)
|
||||
var K8SResource []dbmodel.K8sResource
|
||||
var ConvertResource []api_model.ConvertResource
|
||||
for _, k8sResourceObject := range k8sResourceObjects {
|
||||
if k8sResourceObject.Error != "" {
|
||||
continue
|
||||
}
|
||||
var cms []corev1.ConfigMap
|
||||
var hpas []autoscalingv1.HorizontalPodAutoscaler
|
||||
for _, buildResource := range k8sResourceObject.BuildResources {
|
||||
if buildResource.Resource.GetKind() == api_model.ConfigMap {
|
||||
var cm corev1.ConfigMap
|
||||
cmJSON, _ := json.Marshal(buildResource.Resource)
|
||||
json.Unmarshal(cmJSON, &cm)
|
||||
cms = append(cms, cm)
|
||||
continue
|
||||
}
|
||||
if buildResource.Resource.GetKind() == api_model.HorizontalPodAutoscaler {
|
||||
var hpa autoscalingv1.HorizontalPodAutoscaler
|
||||
cmJSON, _ := json.Marshal(buildResource.Resource)
|
||||
json.Unmarshal(cmJSON, &hpa)
|
||||
hpas = append(hpas, hpa)
|
||||
}
|
||||
}
|
||||
|
||||
for _, buildResource := range k8sResourceObject.BuildResources {
|
||||
errorOverview := "创建成功"
|
||||
state := 1
|
||||
switch buildResource.Resource.GetKind() {
|
||||
case api_model.Deployment:
|
||||
deployJSON, _ := json.Marshal(buildResource.Resource)
|
||||
var deployObject appv1.Deployment
|
||||
json.Unmarshal(deployJSON, &deployObject)
|
||||
basic := api_model.BasicManagement{
|
||||
ResourceType: api_model.Deployment,
|
||||
Replicas: deployObject.Spec.Replicas,
|
||||
Memory: deployObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: deployObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: deployObject.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(deployObject.Spec.Template.Spec.Containers[0].Command, deployObject.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := api_model.YamlResourceParameter{
|
||||
ComponentsCR: &ConvertResource,
|
||||
Basic: basic,
|
||||
Template: deployObject.Spec.Template,
|
||||
Namespace: yamlResource.Namespace,
|
||||
Name: buildResource.Resource.GetName(),
|
||||
RsLabel: deployObject.Labels,
|
||||
HPAs: hpas,
|
||||
CMs: cms,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
case api_model.Job:
|
||||
jobJSON, _ := json.Marshal(buildResource.Resource)
|
||||
var jobObject batchv1.Job
|
||||
json.Unmarshal(jobJSON, &jobObject)
|
||||
basic := api_model.BasicManagement{
|
||||
ResourceType: api_model.Job,
|
||||
Replicas: jobObject.Spec.Completions,
|
||||
Memory: jobObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: jobObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: jobObject.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(jobObject.Spec.Template.Spec.Containers[0].Command, jobObject.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := api_model.YamlResourceParameter{
|
||||
ComponentsCR: &ConvertResource,
|
||||
Basic: basic,
|
||||
Template: jobObject.Spec.Template,
|
||||
Namespace: yamlResource.Namespace,
|
||||
Name: buildResource.Resource.GetName(),
|
||||
RsLabel: jobObject.Labels,
|
||||
HPAs: hpas,
|
||||
CMs: cms,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
case api_model.CronJob:
|
||||
cjJSON, _ := json.Marshal(buildResource.Resource)
|
||||
var cjObject v1beta1.CronJob
|
||||
json.Unmarshal(cjJSON, &cjObject)
|
||||
basic := api_model.BasicManagement{
|
||||
ResourceType: api_model.CronJob,
|
||||
Replicas: cjObject.Spec.JobTemplate.Spec.Completions,
|
||||
Memory: cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command, cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := api_model.YamlResourceParameter{
|
||||
ComponentsCR: &ConvertResource,
|
||||
Basic: basic,
|
||||
Template: cjObject.Spec.JobTemplate.Spec.Template,
|
||||
Namespace: yamlResource.Namespace,
|
||||
Name: buildResource.Resource.GetName(),
|
||||
RsLabel: cjObject.Labels,
|
||||
HPAs: hpas,
|
||||
CMs: cms,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
case api_model.StateFulSet:
|
||||
sfsJSON, _ := json.Marshal(buildResource.Resource)
|
||||
var sfsObject appv1.StatefulSet
|
||||
json.Unmarshal(sfsJSON, &sfsObject)
|
||||
basic := api_model.BasicManagement{
|
||||
ResourceType: api_model.StateFulSet,
|
||||
Replicas: sfsObject.Spec.Replicas,
|
||||
Memory: sfsObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value() / 1024 / 1024,
|
||||
CPU: sfsObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().Value(),
|
||||
Image: sfsObject.Spec.Template.Spec.Containers[0].Image,
|
||||
Cmd: strings.Join(append(sfsObject.Spec.Template.Spec.Containers[0].Command, sfsObject.Spec.Template.Spec.Containers[0].Args...), " "),
|
||||
}
|
||||
parameter := api_model.YamlResourceParameter{
|
||||
ComponentsCR: &ConvertResource,
|
||||
Basic: basic,
|
||||
Template: sfsObject.Spec.Template,
|
||||
Namespace: yamlResource.Namespace,
|
||||
Name: buildResource.Resource.GetName(),
|
||||
RsLabel: sfsObject.Labels,
|
||||
HPAs: hpas,
|
||||
CMs: cms,
|
||||
}
|
||||
c.PodTemplateSpecResource(parameter)
|
||||
default:
|
||||
if yamlImport {
|
||||
resource, err := c.ResourceCreate(buildResource, yamlResource.Namespace)
|
||||
if err != nil {
|
||||
errorOverview = err.Error()
|
||||
state = api_model.CreateError
|
||||
} else {
|
||||
buildResource.Resource = resource
|
||||
}
|
||||
}
|
||||
kubernetesResourcesYAML, err := ObjectToJSONORYaml("yaml", buildResource.Resource)
|
||||
if err != nil {
|
||||
logrus.Errorf("namespace:%v %v:%v error: %v", yamlResource.Namespace, buildResource.Resource.GetKind(), buildResource.Resource.GetName(), err)
|
||||
}
|
||||
K8SResource = append(K8SResource, dbmodel.K8sResource{
|
||||
Name: buildResource.Resource.GetName(),
|
||||
Kind: buildResource.Resource.GetKind(),
|
||||
Content: kubernetesResourcesYAML,
|
||||
State: state,
|
||||
ErrorOverview: errorOverview,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
logrus.Infof("AppYamlResourceDetailed end")
|
||||
return api_model.ApplicationResource{
|
||||
K8SResource,
|
||||
ConvertResource,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//AppYamlResourceImport -
|
||||
func (c *clusterAction) AppYamlResourceImport(yamlResource api_model.YamlResource, components api_model.ApplicationResource) (api_model.AppComponent, *util.APIHandleError) {
|
||||
logrus.Infof("AppYamlResourceImport begin")
|
||||
app, err := db.GetManager().ApplicationDao().GetAppByID(yamlResource.AppID)
|
||||
if err != nil {
|
||||
return api_model.AppComponent{}, &util.APIHandleError{Code: 400, Err: fmt.Errorf("GetAppByID error %v", err)}
|
||||
}
|
||||
var ar api_model.AppComponent
|
||||
err = db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
|
||||
k8sResource, err := c.CreateK8sResource(tx, components.KubernetesResources, app.AppID)
|
||||
if err != nil {
|
||||
logrus.Errorf("create K8sResources err:%v", err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create K8sResources err:%v", err)}
|
||||
}
|
||||
var componentAttributes []api_model.ComponentAttributes
|
||||
for _, componentResource := range components.ConvertResource {
|
||||
component, err := c.CreateComponent(app, yamlResource.TenantID, componentResource, yamlResource.Namespace, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
return &util.APIHandleError{Code: 400, Err: fmt.Errorf("create app error:%v", err)}
|
||||
}
|
||||
c.createENV(componentResource.ENVManagement, component)
|
||||
c.createConfig(componentResource.ConfigManagement, component)
|
||||
c.createPort(componentResource.PortManagement, component)
|
||||
componentResource.TelescopicManagement.RuleID = c.createTelescopic(componentResource.TelescopicManagement, component)
|
||||
componentResource.HealthyCheckManagement.ProbeID = c.createHealthyCheck(componentResource.HealthyCheckManagement, component)
|
||||
c.createK8sAttributes(componentResource.ComponentK8sAttributesManagement, yamlResource.TenantID, component)
|
||||
componentAttributes = append(componentAttributes, api_model.ComponentAttributes{
|
||||
TS: component,
|
||||
Image: componentResource.BasicManagement.Image,
|
||||
Cmd: componentResource.BasicManagement.Cmd,
|
||||
ENV: componentResource.ENVManagement,
|
||||
Config: componentResource.ConfigManagement,
|
||||
Port: componentResource.PortManagement,
|
||||
Telescopic: componentResource.TelescopicManagement,
|
||||
HealthyCheck: componentResource.HealthyCheckManagement,
|
||||
ComponentK8sAttributes: componentResource.ComponentK8sAttributesManagement,
|
||||
})
|
||||
}
|
||||
ar = api_model.AppComponent{
|
||||
App: app,
|
||||
K8sResources: k8sResource,
|
||||
Component: componentAttributes,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return api_model.AppComponent{}, &util.APIHandleError{Code: 400, Err: fmt.Errorf("app yaml resource import error:%v", err)}
|
||||
}
|
||||
logrus.Infof("AppYamlResourceImport end")
|
||||
return ar, nil
|
||||
}
|
||||
|
||||
//YamlToResource -
|
||||
func (c *clusterAction) YamlToResource(yamlResource api_model.YamlResource) []api_model.K8sResourceObject {
|
||||
yamlDirectoryPath := path.Join("/grdata/package_build/temp/events", yamlResource.EventID, "*")
|
||||
yamlFilesPath, _ := filepath.Glob(yamlDirectoryPath)
|
||||
var fileBuildResourceList []api_model.K8sResourceObject
|
||||
for _, yamlFilePath := range yamlFilesPath {
|
||||
pathSplitList := strings.Split(yamlFilePath, "/")
|
||||
fileName := pathSplitList[len(pathSplitList)-1]
|
||||
yamlFileBytes, err := ioutil.ReadFile(yamlFilePath)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: nil,
|
||||
Error: err.Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
dc, err := dynamic.NewForConfig(c.config)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: nil,
|
||||
Error: err.Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
decoder := yamlt.NewYAMLOrJSONDecoder(bytes.NewReader(yamlFileBytes), 1000)
|
||||
var buildResourceList []api_model.BuildResource
|
||||
for {
|
||||
var rawObj runtime.RawExtension
|
||||
if err = decoder.Decode(&rawObj); err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
break
|
||||
}
|
||||
logrus.Errorf("%v", err)
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: nil,
|
||||
Error: err.Error(),
|
||||
})
|
||||
break
|
||||
}
|
||||
obj, gvk, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: nil,
|
||||
Error: err.Error(),
|
||||
})
|
||||
break
|
||||
}
|
||||
unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: nil,
|
||||
Error: err.Error(),
|
||||
})
|
||||
break
|
||||
}
|
||||
unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap}
|
||||
buildResourceList = append(buildResourceList, api_model.BuildResource{
|
||||
Resource: unstructuredObj,
|
||||
State: api_model.CreateError,
|
||||
ErrorOverview: "",
|
||||
Dri: nil,
|
||||
DC: dc,
|
||||
GVK: gvk,
|
||||
})
|
||||
}
|
||||
fileBuildResourceList = append(fileBuildResourceList, api_model.K8sResourceObject{
|
||||
FileName: fileName,
|
||||
BuildResources: buildResourceList,
|
||||
Error: "",
|
||||
})
|
||||
}
|
||||
return fileBuildResourceList
|
||||
}
|
||||
|
||||
//ResourceCreate -
|
||||
func (c *clusterAction) ResourceCreate(buildResource api_model.BuildResource, namespace string) (*unstructured.Unstructured, error) {
|
||||
mapping, err := c.mapper.RESTMapping(buildResource.GVK.GroupKind(), buildResource.GVK.Version)
|
||||
if err != nil {
|
||||
logrus.Errorf("%v", err)
|
||||
return nil, err
|
||||
}
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
|
||||
buildResource.Resource.SetNamespace(namespace)
|
||||
buildResource.Dri = buildResource.DC.Resource(mapping.Resource).Namespace(buildResource.Resource.GetNamespace())
|
||||
} else {
|
||||
buildResource.Dri = buildResource.DC.Resource(mapping.Resource)
|
||||
}
|
||||
obj, err := buildResource.Dri.Create(context.Background(), buildResource.Resource, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj, nil
|
||||
}
|
@ -241,23 +241,24 @@ func (e *ComponentEnv) DbModel(tenantID, componentID string) *dbmodel.TenantServ
|
||||
|
||||
// Component All attributes related to the component
|
||||
type Component struct {
|
||||
ComponentBase ComponentBase `json:"component_base"`
|
||||
HTTPRules []AddHTTPRuleStruct `json:"http_rules"`
|
||||
TCPRules []AddTCPRuleStruct `json:"tcp_rules"`
|
||||
HTTPRuleConfigs []HTTPRuleConfig `json:"http_rule_configs"`
|
||||
Monitors []AddServiceMonitorRequestStruct `json:"monitors"`
|
||||
Ports []TenantServicesPort `json:"ports"`
|
||||
Relations []TenantComponentRelation `json:"relations"`
|
||||
Envs []ComponentEnv `json:"envs"`
|
||||
Probes []ServiceProbe `json:"probes"`
|
||||
AppConfigGroupRels []AppConfigGroupRelations `json:"app_config_groups"`
|
||||
Labels []ComponentLabel `json:"labels"`
|
||||
Plugins []ComponentPlugin `json:"plugins"`
|
||||
AutoScaleRule AutoScalerRule `json:"auto_scale_rule"`
|
||||
ConfigFiles []ComponentConfigFile `json:"config_files"`
|
||||
VolumeRelations []VolumeRelation `json:"volume_relations"`
|
||||
Volumes []ComponentVolume `json:"volumes"`
|
||||
Endpoint *Endpoints `json:"endpoint"`
|
||||
ComponentBase ComponentBase `json:"component_base"`
|
||||
HTTPRules []AddHTTPRuleStruct `json:"http_rules"`
|
||||
TCPRules []AddTCPRuleStruct `json:"tcp_rules"`
|
||||
HTTPRuleConfigs []HTTPRuleConfig `json:"http_rule_configs"`
|
||||
Monitors []AddServiceMonitorRequestStruct `json:"monitors"`
|
||||
Ports []TenantServicesPort `json:"ports"`
|
||||
Relations []TenantComponentRelation `json:"relations"`
|
||||
Envs []ComponentEnv `json:"envs"`
|
||||
Probes []ServiceProbe `json:"probes"`
|
||||
AppConfigGroupRels []AppConfigGroupRelations `json:"app_config_groups"`
|
||||
Labels []ComponentLabel `json:"labels"`
|
||||
Plugins []ComponentPlugin `json:"plugins"`
|
||||
AutoScaleRule AutoScalerRule `json:"auto_scale_rule"`
|
||||
ConfigFiles []ComponentConfigFile `json:"config_files"`
|
||||
VolumeRelations []VolumeRelation `json:"volume_relations"`
|
||||
Volumes []ComponentVolume `json:"volumes"`
|
||||
Endpoint *Endpoints `json:"endpoint"`
|
||||
ComponentK8sAttributes []ComponentK8sAttribute `json:"component_k8s_attributes"`
|
||||
}
|
||||
|
||||
// SyncComponentReq -
|
||||
@ -265,3 +266,34 @@ type SyncComponentReq struct {
|
||||
Components []*Component `json:"components"`
|
||||
DeleteComponentIDs []string `json:"delete_component_ids"`
|
||||
}
|
||||
|
||||
// ComponentK8sAttribute -
|
||||
type ComponentK8sAttribute struct {
|
||||
// Name Define the attribute name, which is currently supported
|
||||
// [nodeSelector/labels/tolerations/volumes/serviceAccountName/privileged/affinity/volumeMounts]
|
||||
// The field name should be the same as that in the K8s resource yaml file.
|
||||
Name string `json:"name"`
|
||||
|
||||
// The field type defines how the attribute is stored. Currently, `json/yaml/string` are supported
|
||||
SaveType string `json:"save_type"`
|
||||
|
||||
// Define the attribute value, which is stored in the database.
|
||||
// The value is stored in the database in the form of `json/yaml/string`.
|
||||
AttributeValue string `json:"attribute_value"`
|
||||
}
|
||||
|
||||
// DbModel return database model
|
||||
func (k *ComponentK8sAttribute) DbModel(tenantID, componentID string) *dbmodel.ComponentK8sAttributes {
|
||||
return &dbmodel.ComponentK8sAttributes{
|
||||
TenantID: tenantID,
|
||||
ComponentID: componentID,
|
||||
Name: k.Name,
|
||||
SaveType: k.SaveType,
|
||||
AttributeValue: k.AttributeValue,
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteK8sAttributeReq -
|
||||
type DeleteK8sAttributeReq struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
133
api/model/convert_resource.go
Normal file
133
api/model/convert_resource.go
Normal file
@ -0,0 +1,133 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/goodrain/rainbond/db/model"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
//BasicManagement -
|
||||
type BasicManagement struct {
|
||||
ResourceType string `json:"resource_type"`
|
||||
Replicas *int32 `json:"replicas"`
|
||||
Image string `json:"image"`
|
||||
Memory int64 `json:"memory"`
|
||||
Cmd string `json:"command"`
|
||||
CPU int64 `json:"cpu"`
|
||||
JobStrategy JobStrategy `json:"job_strategy"`
|
||||
}
|
||||
|
||||
//PortManagement -
|
||||
type PortManagement struct {
|
||||
Port int32 `json:"port"`
|
||||
Protocol string `json:"protocol"`
|
||||
Inner bool `json:"inner"`
|
||||
Outer bool `json:"outer"`
|
||||
}
|
||||
|
||||
//ENVManagement -
|
||||
type ENVManagement struct {
|
||||
ENVKey string `json:"env_key"`
|
||||
ENVValue string `json:"env_value"`
|
||||
ENVExplain string `json:"env_explain"`
|
||||
}
|
||||
|
||||
//ConfigManagement -
|
||||
type ConfigManagement struct {
|
||||
ConfigName string `json:"config_name"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
Mode int32 `json:"mode"`
|
||||
ConfigValue string `json:"config_value"`
|
||||
}
|
||||
|
||||
//HealthyCheckManagement -
|
||||
type HealthyCheckManagement struct {
|
||||
Status int `json:"status"`
|
||||
ProbeID string `json:"probe_id"`
|
||||
Port int `json:"port"`
|
||||
Path string `json:"path"`
|
||||
HTTPHeader string `json:"http_header"`
|
||||
Command string `json:"cmd"`
|
||||
DetectionMethod string `json:"detection_method"`
|
||||
Mode string `json:"mode"`
|
||||
InitialDelaySecond int `json:"initial_delay_second"`
|
||||
PeriodSecond int `json:"period_second"`
|
||||
TimeoutSecond int `json:"timeout_second"`
|
||||
SuccessThreshold int `json:"success_threshold"`
|
||||
FailureThreshold int `json:"failure_threshold"`
|
||||
}
|
||||
|
||||
//TelescopicManagement -
|
||||
type TelescopicManagement struct {
|
||||
Enable bool `json:"enable"`
|
||||
RuleID string `json:"rule_id"`
|
||||
MinReplicas int32 `json:"min_replicas"`
|
||||
MaxReplicas int32 `json:"max_replicas"`
|
||||
CPUOrMemory []*model.TenantServiceAutoscalerRuleMetrics `json:"cpu_or_memory"`
|
||||
}
|
||||
|
||||
//KubernetesResources -
|
||||
type KubernetesResources struct {
|
||||
Name string `json:"name"`
|
||||
Spec v1.ServiceSpec `json:"spec"`
|
||||
Namespace string `json:"namespace"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
Kind string `json:"kind"`
|
||||
APIVersion string `json:"api_version"`
|
||||
GenerateName string `json:"generate_name"`
|
||||
UID types.UID `json:"uid"`
|
||||
ResourceVersion string `json:"resource_version"`
|
||||
Generation int64 `json:"generation"`
|
||||
CreationTimestamp metav1.Time `json:"creation_timestamp"`
|
||||
DeletionTimestamp *metav1.Time `json:"deletion_timestamp"`
|
||||
DeletionGracePeriodSeconds *int64 `json:"deletion_grace_period_seconds"`
|
||||
OwnerReferences []metav1.OwnerReference `json:"owner_references"`
|
||||
Finalizers []string `json:"finalizers"`
|
||||
ClusterName string `json:"cluster_name"`
|
||||
}
|
||||
|
||||
//ApplicationResource -
|
||||
type ApplicationResource struct {
|
||||
KubernetesResources []model.K8sResource `json:"kubernetes_resources"`
|
||||
ConvertResource []ConvertResource `json:"convert_resource"`
|
||||
}
|
||||
|
||||
//ConvertResource -
|
||||
type ConvertResource struct {
|
||||
ComponentsName string `json:"components_name"`
|
||||
BasicManagement BasicManagement `json:"basic_management"`
|
||||
PortManagement []PortManagement `json:"port_management"`
|
||||
ENVManagement []ENVManagement `json:"env_management"`
|
||||
ConfigManagement []ConfigManagement `json:"config_management"`
|
||||
HealthyCheckManagement HealthyCheckManagement `json:"health_check_management"`
|
||||
TelescopicManagement TelescopicManagement `json:"telescopic_management"`
|
||||
ComponentK8sAttributesManagement []*model.ComponentK8sAttributes `json:"component_k8s_attributes_management"`
|
||||
}
|
||||
|
||||
//ComponentAttributes -
|
||||
type ComponentAttributes struct {
|
||||
TS *model.TenantServices `json:"ts"`
|
||||
Image string `json:"image"`
|
||||
Cmd string `json:"cmd"`
|
||||
ENV []ENVManagement `json:"env"`
|
||||
Config []ConfigManagement `json:"config"`
|
||||
Port []PortManagement `json:"port"`
|
||||
Telescopic TelescopicManagement `json:"telescopic"`
|
||||
HealthyCheck HealthyCheckManagement `json:"healthy_check"`
|
||||
ComponentK8sAttributes []*model.ComponentK8sAttributes `json:"component_k8s_attributes"`
|
||||
}
|
||||
|
||||
//AppComponent -
|
||||
type AppComponent struct {
|
||||
App *model.Application `json:"app"`
|
||||
K8sResources []model.K8sResource `json:"k8s_resources"`
|
||||
Component []ComponentAttributes `json:"component"`
|
||||
}
|
||||
|
||||
//ReturnResourceImport -
|
||||
type ReturnResourceImport struct {
|
||||
Tenant *model.Tenants `json:"tenant"`
|
||||
App []AppComponent `json:"app"`
|
||||
}
|
@ -359,6 +359,7 @@ type ServiceStruct struct {
|
||||
HTTPRules []AddHTTPRuleStruct `json:"http_rules" validate:"http_rules"`
|
||||
TCPRules []AddTCPRuleStruct `json:"tcp_rules" validate:"tcp_rules"`
|
||||
K8sComponentName string `json:"k8s_component_name" validate:"k8s_component_name"`
|
||||
JobStrategy string `json:"job_strategy" validate:"job_strategy"`
|
||||
}
|
||||
|
||||
// Endpoints holds third-party service endpoints or configuraion to get endpoints.
|
||||
@ -449,6 +450,55 @@ type DeleteServicePort struct {
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
//AddHandleResource -
|
||||
type AddHandleResource struct {
|
||||
Namespace string `json:"namespace"`
|
||||
AppID string `json:"app_id"`
|
||||
ResourceYaml string `json:"resource_yaml"`
|
||||
}
|
||||
|
||||
//HandleResource -
|
||||
type HandleResource struct {
|
||||
Name string `json:"name"`
|
||||
AppID string `json:"app_id"`
|
||||
Kind string `json:"kind"`
|
||||
Namespace string `json:"namespace"`
|
||||
ResourceYaml string `json:"resource_yaml"`
|
||||
}
|
||||
|
||||
// SyncResources -
|
||||
type SyncResources struct {
|
||||
K8sResources []HandleResource `json:"k8s_resources"`
|
||||
}
|
||||
|
||||
//YamlResource -
|
||||
type YamlResource struct {
|
||||
EventID string `json:"event_id"`
|
||||
AppID string `json:"region_app_id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
const (
|
||||
//CreateSuccess -
|
||||
CreateSuccess = 1
|
||||
//UpdateSuccess -
|
||||
UpdateSuccess = 2
|
||||
//CreateError -
|
||||
CreateError = 3
|
||||
//UpdateError -
|
||||
UpdateError = 4
|
||||
)
|
||||
|
||||
// JobStrategy -
|
||||
type JobStrategy struct {
|
||||
Schedule string `json:"schedule"`
|
||||
BackoffLimit string `json:"backoff_limit"`
|
||||
Parallelism string `json:"parallelism"`
|
||||
ActiveDeadlineSeconds string `json:"active_deadline_seconds"`
|
||||
Completions string `json:"completions"`
|
||||
}
|
||||
|
||||
//TenantResources TenantResources
|
||||
// swagger:parameters tenantResources
|
||||
type TenantResources struct {
|
||||
@ -980,7 +1030,7 @@ type ServiceCheckStruct struct {
|
||||
//检测来源类型
|
||||
// in: body
|
||||
// required: true
|
||||
SourceType string `json:"source_type" validate:"source_type|required|in:docker-run,docker-compose,sourcecode,third-party-service"`
|
||||
SourceType string `json:"source_type" validate:"source_type|required|in:docker-run,docker-compose,sourcecode,third-party-service,package_build"`
|
||||
|
||||
CheckOS string `json:"check_os"`
|
||||
// 检测来源定义,
|
||||
|
32
api/model/namespace_resource.go
Normal file
32
api/model/namespace_resource.go
Normal file
@ -0,0 +1,32 @@
|
||||
package model
|
||||
|
||||
const (
|
||||
//Deployment -
|
||||
Deployment = "Deployment"
|
||||
//Job -
|
||||
Job = "Job"
|
||||
//CronJob -
|
||||
CronJob = "CronJob"
|
||||
//StateFulSet -
|
||||
StateFulSet = "StatefulSet"
|
||||
//Service -
|
||||
Service = "Service"
|
||||
//PVC -
|
||||
PVC = "PersistentVolumeClaim"
|
||||
//Ingress -
|
||||
Ingress = "Ingress"
|
||||
//NetworkPolicy -
|
||||
NetworkPolicy = "NetworkPolicy"
|
||||
//ConfigMap -
|
||||
ConfigMap = "ConfigMap"
|
||||
//Secret -
|
||||
Secret = "Secret"
|
||||
//ServiceAccount -
|
||||
ServiceAccount = "ServiceAccount"
|
||||
//RoleBinding -
|
||||
RoleBinding = "RoleBinding"
|
||||
//HorizontalPodAutoscaler -
|
||||
HorizontalPodAutoscaler = "HorizontalPodAutoscaler"
|
||||
//Role -
|
||||
Role = "Role"
|
||||
)
|
90
api/model/resource_handle.go
Normal file
90
api/model/resource_handle.go
Normal file
@ -0,0 +1,90 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
//LabelResource -
|
||||
type LabelResource struct {
|
||||
Workloads WorkLoadsResource `json:"workloads,omitempty"`
|
||||
Others OtherResource `json:"others,omitempty"`
|
||||
UnSupport map[string][]string `json:"un_support"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
//LabelWorkloadsResourceProcess -
|
||||
type LabelWorkloadsResourceProcess struct {
|
||||
Deployments map[string][]string `json:"deployments,omitempty"`
|
||||
Jobs map[string][]string `json:"jobs,omitempty"`
|
||||
CronJobs map[string][]string `json:"cronJobs,omitempty"`
|
||||
StateFulSets map[string][]string `json:"stateFulSets,omitempty"`
|
||||
}
|
||||
|
||||
//LabelOthersResourceProcess -
|
||||
type LabelOthersResourceProcess struct {
|
||||
Services map[string][]string `json:"services,omitempty"`
|
||||
PVC map[string][]string `json:"PVC,omitempty"`
|
||||
Ingresses map[string][]string `json:"ingresses,omitempty"`
|
||||
NetworkPolicies map[string][]string `json:"networkPolicies,omitempty"`
|
||||
ConfigMaps map[string][]string `json:"configMaps,omitempty"`
|
||||
Secrets map[string][]string `json:"secrets,omitempty"`
|
||||
ServiceAccounts map[string][]string `json:"serviceAccounts,omitempty"`
|
||||
RoleBindings map[string][]string `json:"roleBindings,omitempty"`
|
||||
HorizontalPodAutoscalers map[string][]string `json:"horizontalPodAutoscalers,omitempty"`
|
||||
Roles map[string][]string `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
//YamlResourceParameter -
|
||||
type YamlResourceParameter struct {
|
||||
ComponentsCR *[]ConvertResource
|
||||
Basic BasicManagement
|
||||
Template corev1.PodTemplateSpec
|
||||
Namespace string
|
||||
Name string
|
||||
RsLabel map[string]string
|
||||
CMs []corev1.ConfigMap
|
||||
HPAs []autoscalingv1.HorizontalPodAutoscaler
|
||||
}
|
||||
|
||||
//K8sResourceObject -
|
||||
type K8sResourceObject struct {
|
||||
FileName string
|
||||
BuildResources []BuildResource
|
||||
Error string
|
||||
}
|
||||
|
||||
//WorkLoadsResource -
|
||||
type WorkLoadsResource struct {
|
||||
Deployments []string `json:"deployments,omitempty"`
|
||||
Jobs []string `json:"jobs,omitempty"`
|
||||
CronJobs []string `json:"cron_jobs,omitempty"`
|
||||
StateFulSets []string `json:"state_ful_sets,omitempty"`
|
||||
}
|
||||
|
||||
//BuildResource -
|
||||
type BuildResource struct {
|
||||
Resource *unstructured.Unstructured
|
||||
State int
|
||||
ErrorOverview string
|
||||
Dri dynamic.ResourceInterface
|
||||
DC dynamic.Interface
|
||||
GVK *schema.GroupVersionKind
|
||||
}
|
||||
|
||||
//OtherResource -
|
||||
type OtherResource struct {
|
||||
Services []string `json:"services,omitempty"`
|
||||
PVC []string `json:"pvc,omitempty"`
|
||||
Ingresses []string `json:"ingresses,omitempty"`
|
||||
NetworkPolicies []string `json:"network_policies,omitempty"`
|
||||
ConfigMaps []string `json:"config_maps,omitempty"`
|
||||
Secrets []string `json:"secrets,omitempty"`
|
||||
ServiceAccounts []string `json:"service_accounts,omitempty"`
|
||||
RoleBindings []string `json:"role_bindings,omitempty"`
|
||||
HorizontalPodAutoscalers []string `json:"horizontal_pod_autoscalers,omitempty"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
}
|
@ -173,6 +173,7 @@ func (m *Manager) Run() {
|
||||
websocketRouter.Mount("/", websocket.Routes())
|
||||
websocketRouter.Mount("/logs", websocket.LogRoutes())
|
||||
websocketRouter.Mount("/app", websocket.AppRoutes())
|
||||
websocketRouter.Mount("/package_build", websocket.PackageBuildRoutes())
|
||||
if m.conf.WebsocketSSL {
|
||||
logrus.Infof("websocket listen on (HTTPs) %s", m.conf.WebsocketAddr)
|
||||
logrus.Fatal(http.ListenAndServeTLS(m.conf.WebsocketAddr, m.conf.WebsocketCertFile, m.conf.WebsocketKeyFile, websocketRouter))
|
||||
|
@ -314,6 +314,13 @@ func (s *slugBuild) createVolumeAndMount(re *Request, sourceTarFileName string)
|
||||
})
|
||||
}
|
||||
}
|
||||
if re.ServerType == "pkg" {
|
||||
volumeMounts = append(volumeMounts, corev1.VolumeMount{
|
||||
Name: "slug",
|
||||
MountPath: "/tmp/app",
|
||||
SubPath: strings.TrimPrefix(re.RepositoryURL, "/grdata/"),
|
||||
})
|
||||
}
|
||||
return volumes, volumeMounts
|
||||
}
|
||||
|
||||
@ -322,7 +329,7 @@ func (s *slugBuild) runBuildJob(re *Request) error {
|
||||
re.Logger.Info(util.Translation("Start make code package"), map[string]string{"step": "build-exector"})
|
||||
start := time.Now()
|
||||
var sourceTarFileName string
|
||||
if re.ServerType != "oss" {
|
||||
if re.ServerType != "oss" && re.ServerType != "pkg" {
|
||||
var err error
|
||||
sourceTarFileName, err = s.getSourceCodeTarFile(re)
|
||||
if err != nil {
|
||||
|
@ -21,6 +21,8 @@ package exector
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/builder/parser"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@ -31,7 +33,6 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/goodrain/rainbond/builder"
|
||||
"github.com/goodrain/rainbond/builder/build"
|
||||
"github.com/goodrain/rainbond/builder/parser"
|
||||
"github.com/goodrain/rainbond/builder/parser/code"
|
||||
"github.com/goodrain/rainbond/builder/sources"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
@ -95,6 +96,7 @@ func NewSouceCodeBuildItem(in []byte) *SourceCodeBuildItem {
|
||||
Password: gjson.GetBytes(in, "password").String(),
|
||||
TenantID: gjson.GetBytes(in, "tenant_id").String(),
|
||||
ServiceID: gjson.GetBytes(in, "service_id").String(),
|
||||
Configs: gjson.GetBytes(in, "configs").Map(),
|
||||
}
|
||||
envs := gjson.GetBytes(in, "envs").String()
|
||||
be := make(map[string]string)
|
||||
@ -163,6 +165,69 @@ func (i *SourceCodeBuildItem) Run(timeout time.Duration) error {
|
||||
}
|
||||
case "oss":
|
||||
i.commit = Commit{}
|
||||
case "pkg":
|
||||
var filePath string
|
||||
pathSplit := strings.Split(i.CodeSouceInfo.RepositoryURL, "/")
|
||||
eventID := pathSplit[len(pathSplit)-1]
|
||||
// 存放目录
|
||||
tarPath := fmt.Sprintf("/grdata/package_build/components/%s/events", i.ServiceID)
|
||||
// 临时目录
|
||||
oldPath := fmt.Sprintf("/grdata/package_build/temp/events/%s", eventID)
|
||||
// 快速复制原目录
|
||||
copyPath := i.CodeSouceInfo.Configs[i.ServiceID]
|
||||
filePath = fmt.Sprintf("%s/%s", tarPath, eventID)
|
||||
|
||||
if copyPath.Str == "" {
|
||||
files, err := ioutil.ReadDir(filePath)
|
||||
if err != nil {
|
||||
logrus.Errorf("read dir error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
if len(files) == 0 {
|
||||
filePath = oldPath
|
||||
}
|
||||
} else {
|
||||
// 快速复制
|
||||
splitCopyPath := strings.Split(copyPath.Str, "/")
|
||||
splitRes := pathSplit[0 : len(splitCopyPath)-1]
|
||||
modelPath := strings.Join(splitRes, "/")
|
||||
tarCopyPath := fmt.Sprintf("/grdata/package_build/components/%s", i.ServiceID)
|
||||
err := os.MkdirAll(tarCopyPath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := util.CopyDir(modelPath, tarCopyPath); err != nil {
|
||||
logrus.Errorf("copy dir error: %s", err.Error())
|
||||
}
|
||||
filePath = copyPath.Str
|
||||
}
|
||||
packages, err := ioutil.ReadDir(filePath)
|
||||
if err != nil {
|
||||
logrus.Errorf("read dir error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
packageArr := make([]string, 0, 10)
|
||||
for _, dir := range packages {
|
||||
if dir.IsDir() {
|
||||
continue
|
||||
}
|
||||
packageArr = append(packageArr, dir.Name())
|
||||
}
|
||||
if len(packageArr) != 0 {
|
||||
fileName := packageArr[0]
|
||||
file := filePath + "/" + fileName
|
||||
fileMD5 := util.MD5(file)
|
||||
i.commit = Commit{
|
||||
Message: fileName,
|
||||
Hash: fileMD5,
|
||||
}
|
||||
}
|
||||
if copyPath.Str == "" {
|
||||
if err = util.MoveDir(oldPath, tarPath); err != nil {
|
||||
logrus.Errorf("copy dir error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
//default git
|
||||
rs, err := sources.GitCloneOrPull(i.CodeSouceInfo, rbi.GetCodeHome(), i.Logger, 5)
|
||||
@ -186,8 +251,10 @@ func (i *SourceCodeBuildItem) Run(timeout time.Duration) error {
|
||||
}
|
||||
// clean cache code
|
||||
defer func() {
|
||||
if err := os.RemoveAll(rbi.GetCodeHome()); err != nil {
|
||||
logrus.Warningf("remove source code: %v", err)
|
||||
if i.CodeSouceInfo.ServerType != "pkg" {
|
||||
if err := os.RemoveAll(rbi.GetCodeHome()); err != nil {
|
||||
logrus.Warningf("remove source code: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -115,10 +115,12 @@ func (e *exectorManager) serviceCheck(task *pb.TaskMessage) {
|
||||
yamlbody = string(yamlbyte)
|
||||
}
|
||||
pr = parser.CreateDockerComposeParse(yamlbody, e.DockerClient, input.Username, input.Password, logger)
|
||||
case "sourcecode":
|
||||
case "sourcecode" :
|
||||
pr = parser.CreateSourceCodeParse(input.SourceBody, logger)
|
||||
case "third-party-service":
|
||||
pr = parser.CreateThirdPartyServiceParse(input.SourceBody, logger)
|
||||
case "package_build":
|
||||
pr = parser.CreateSourceCodeParse(input.SourceBody, logger)
|
||||
}
|
||||
if pr == nil {
|
||||
logger.Error("Creating component source types is not supported", map[string]string{"step": "callback", "status": "failure"})
|
||||
|
@ -51,8 +51,15 @@ func init() {
|
||||
|
||||
//CheckCodeSpecification 检查语言规范
|
||||
func CheckCodeSpecification(buildPath string, lang Lang, serverType string) Specification {
|
||||
if serverType == "oss" && lang == JavaJar {
|
||||
return common()
|
||||
switch serverType {
|
||||
case "oss":
|
||||
if lang == JavaJar{
|
||||
return common()
|
||||
}
|
||||
case "pkg":
|
||||
if lang == JavaJar || lang == JaveWar{
|
||||
return common()
|
||||
}
|
||||
}
|
||||
if check, ok := specification[lang]; ok {
|
||||
return check(buildPath)
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
@ -110,9 +111,11 @@ func (d *SourceCodeParse) Parse() ParseErrorList {
|
||||
}
|
||||
// The source code is useless after the test is completed, and needs to be deleted.
|
||||
defer func() {
|
||||
if sources.CheckFileExist(buildInfo.GetCodeHome()) {
|
||||
if err := sources.RemoveDir(buildInfo.GetCodeHome()); err != nil {
|
||||
logrus.Warningf("remove source code: %v", err)
|
||||
if csi.ServerType != "pkg"{
|
||||
if sources.CheckFileExist(buildInfo.GetCodeHome()) {
|
||||
if err := sources.RemoveDir(buildInfo.GetCodeHome()); err != nil {
|
||||
logrus.Warningf("remove source code: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -203,6 +206,22 @@ func (d *SourceCodeParse) Parse() ParseErrorList {
|
||||
d.branchs = rs.Branchs
|
||||
return nil
|
||||
}
|
||||
packageFunc :=func() ParseErrorList{
|
||||
var checkPath string
|
||||
checkPath = buildInfo.RepostoryURL
|
||||
pathSplit := strings.Split(buildInfo.RepostoryURL,"/")
|
||||
eventID := pathSplit[len(pathSplit)-1]
|
||||
files, err := ioutil.ReadDir(checkPath)
|
||||
if err != nil {
|
||||
logrus.Warn("check package error", err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
// 第一次上传在临时目录下检测
|
||||
checkPath = fmt.Sprintf("/grdata/package_build/temp/events/%s", eventID)
|
||||
}
|
||||
buildInfo.CodeHome = checkPath
|
||||
return ParseErrorList{}
|
||||
}
|
||||
ossFunc := func() ParseErrorList {
|
||||
g := got.NewWithContext(context.Background())
|
||||
util.CheckAndCreateDir(buildInfo.GetCodeHome())
|
||||
@ -260,6 +279,10 @@ func (d *SourceCodeParse) Parse() ParseErrorList {
|
||||
if err := ossFunc(); err != nil && err.IsFatalError() {
|
||||
return err
|
||||
}
|
||||
case "pkg":
|
||||
if err := packageFunc(); err != nil && err.IsFatalError() {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
//default git
|
||||
logrus.Warningf("do not get void server type,default use git")
|
||||
|
@ -21,6 +21,7 @@ package sources
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/tidwall/gjson"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -53,11 +54,12 @@ import (
|
||||
|
||||
//CodeSourceInfo 代码源信息
|
||||
type CodeSourceInfo struct {
|
||||
ServerType string `json:"server_type"`
|
||||
RepositoryURL string `json:"repository_url"`
|
||||
Branch string `json:"branch"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
ServerType string `json:"server_type"`
|
||||
RepositoryURL string `json:"repository_url"`
|
||||
Branch string `json:"branch"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Configs map[string]gjson.Result `json:"configs"`
|
||||
//避免项目之间冲突,代码缓存目录提高到租户
|
||||
TenantID string `json:"tenant_id"`
|
||||
ServiceID string `json:"service_id"`
|
||||
@ -428,12 +430,11 @@ func GetPrivateFile(tenantID string) string {
|
||||
}
|
||||
if ok, _ := util.FileExists(path.Join(home, "/.ssh/"+tenantID)); ok {
|
||||
return path.Join(home, "/.ssh/"+tenantID)
|
||||
} else {
|
||||
if ok, _ := util.FileExists(path.Join(home, "/.ssh/builder_rsa")); ok {
|
||||
return path.Join(home, "/.ssh/builder_rsa")
|
||||
}
|
||||
return path.Join(home, "/.ssh/id_rsa")
|
||||
}
|
||||
if ok, _ := util.FileExists(path.Join(home, "/.ssh/builder_rsa")); ok {
|
||||
return path.Join(home, "/.ssh/builder_rsa")
|
||||
}
|
||||
return path.Join(home, "/.ssh/id_rsa")
|
||||
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,13 @@ func (r *RepostoryBuildInfo) GetProtocol() string {
|
||||
//CreateRepostoryBuildInfo 创建源码编译信息
|
||||
//repoType git or svn
|
||||
func CreateRepostoryBuildInfo(repoURL, repoType, branch, tenantID string, ServiceID string) (*RepostoryBuildInfo, error) {
|
||||
if repoType == "pkg" {
|
||||
return &RepostoryBuildInfo{
|
||||
RepostoryURL: repoURL,
|
||||
RepostoryURLType: repoType,
|
||||
CodeHome: repoURL,
|
||||
}, nil
|
||||
}
|
||||
// repoURL= github.com/goodrain/xxx.git?dir=home
|
||||
ep, err := transport.NewEndpoint(repoURL)
|
||||
if err != nil {
|
||||
|
@ -20,12 +20,11 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
|
||||
rainbondscheme "github.com/goodrain/rainbond/pkg/generated/clientset/versioned/scheme"
|
||||
|
||||
"github.com/goodrain/rainbond/api/controller"
|
||||
"github.com/goodrain/rainbond/api/db"
|
||||
"github.com/goodrain/rainbond/api/discover"
|
||||
@ -34,6 +33,7 @@ import (
|
||||
"github.com/goodrain/rainbond/cmd/api/option"
|
||||
"github.com/goodrain/rainbond/event"
|
||||
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
|
||||
rainbondscheme "github.com/goodrain/rainbond/pkg/generated/clientset/versioned/scheme"
|
||||
etcdutil "github.com/goodrain/rainbond/util/etcd"
|
||||
k8sutil "github.com/goodrain/rainbond/util/k8s"
|
||||
"github.com/goodrain/rainbond/worker/client"
|
||||
@ -79,6 +79,7 @@ func Run(s *option.APIServer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rainbondClient := versioned.NewForConfigOrDie(config)
|
||||
|
||||
// k8s runtime client
|
||||
@ -91,6 +92,12 @@ func Run(s *option.APIServer) error {
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "create k8s client")
|
||||
}
|
||||
// rest mapper
|
||||
gr, err := restmapper.GetAPIGroupResources(clientset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapper := restmapper.NewDiscoveryRESTMapper(gr)
|
||||
|
||||
if err := event.NewManager(event.EventConfig{
|
||||
EventLogServers: s.Config.EventLogServers,
|
||||
@ -121,7 +128,7 @@ func Run(s *option.APIServer) error {
|
||||
//初始化 middleware
|
||||
handler.InitProxy(s.Config)
|
||||
//创建handle
|
||||
if err := handler.InitHandle(s.Config, etcdClientArgs, cli, etcdcli, clientset, rainbondClient, k8sClient); err != nil {
|
||||
if err := handler.InitHandle(s.Config, etcdClientArgs, cli, etcdcli, clientset, rainbondClient, k8sClient, config, mapper); err != nil {
|
||||
logrus.Errorf("init all handle error, %v", err)
|
||||
return err
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ type ApplicationDao interface {
|
||||
GetByServiceID(sid string) (*model.Application, error)
|
||||
ListByAppIDs(appIDs []string) ([]*model.Application, error)
|
||||
IsK8sAppDuplicate(tenantID, AppID, k8sApp string) bool
|
||||
GetAppByName(tenantID, k8sAppName string) (*model.Application, error)
|
||||
}
|
||||
|
||||
//AppConfigGroupDao Application config group Dao
|
||||
@ -621,3 +622,21 @@ type TenantServiceMonitorDao interface {
|
||||
DeleteByComponentIDs(componentIDs []string) error
|
||||
CreateOrUpdateMonitorInBatch(monitors []*model.TenantServiceMonitor) error
|
||||
}
|
||||
|
||||
// ComponentK8sAttributeDao -
|
||||
type ComponentK8sAttributeDao interface {
|
||||
Dao
|
||||
GetByComponentIDAndName(componentID, name string) (*model.ComponentK8sAttributes, error)
|
||||
CreateOrUpdateAttributesInBatch(attributes []*model.ComponentK8sAttributes) error
|
||||
DeleteByComponentIDAndName(componentID, name string) error
|
||||
DeleteByComponentIDs(componentIDs []string) error
|
||||
}
|
||||
|
||||
// K8sResourceDao -
|
||||
type K8sResourceDao interface {
|
||||
Dao
|
||||
ListByAppID(appID string) ([]model.K8sResource, error)
|
||||
CreateK8sResourceInBatch(k8sResources []*model.K8sResource) error
|
||||
DeleteK8sResourceInBatch(appID, name string, kind string) error
|
||||
GetK8sResourceByNameInBatch(appID, name, kind string) ([]model.K8sResource, error)
|
||||
}
|
||||
|
5
db/db.go
5
db/db.go
@ -47,6 +47,8 @@ type Manager interface {
|
||||
AppConfigGroupServiceDaoTransactions(db *gorm.DB) dao.AppConfigGroupServiceDao
|
||||
AppConfigGroupItemDao() dao.AppConfigGroupItemDao
|
||||
AppConfigGroupItemDaoTransactions(db *gorm.DB) dao.AppConfigGroupItemDao
|
||||
K8sResourceDao() dao.K8sResourceDao
|
||||
K8sResourceDaoTransactions(db *gorm.DB) dao.K8sResourceDao
|
||||
EnterpriseDao() dao.EnterpriseDao
|
||||
TenantDao() dao.TenantDao
|
||||
TenantDaoTransactions(db *gorm.DB) dao.TenantDao
|
||||
@ -137,6 +139,9 @@ type Manager interface {
|
||||
|
||||
TenantServiceMonitorDao() dao.TenantServiceMonitorDao
|
||||
TenantServiceMonitorDaoTransactions(db *gorm.DB) dao.TenantServiceMonitorDao
|
||||
|
||||
ComponentK8sAttributeDao() dao.ComponentK8sAttributeDao
|
||||
ComponentK8sAttributeDaoTransactions(db *gorm.DB) dao.ComponentK8sAttributeDao
|
||||
}
|
||||
|
||||
var defaultManager Manager
|
||||
|
@ -1,3 +1,21 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2020-2022 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
@ -73,7 +91,27 @@ type ApplicationConfigGroup struct {
|
||||
Enable bool `gorm:"column:enable" json:"enable"`
|
||||
}
|
||||
|
||||
// TableName return tableName "application"
|
||||
// TableName return tableName "app_config_group"
|
||||
func (t *ApplicationConfigGroup) TableName() string {
|
||||
return "app_config_group"
|
||||
}
|
||||
|
||||
// K8sResource Save k8s resources under the application
|
||||
type K8sResource struct {
|
||||
Model
|
||||
AppID string `gorm:"column:app_id" json:"app_id"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
// The resource kind is the same as that in k8s cluster
|
||||
Kind string `gorm:"column:kind" json:"kind"`
|
||||
// Yaml file for the storage resource
|
||||
Content string `gorm:"column:content;type:longtext" json:"content"`
|
||||
// resource create error overview
|
||||
ErrorOverview string `gorm:"column:status;type:longtext" json:"error_overview"`
|
||||
//whether it was created successfully
|
||||
State int `gorm:"column:success;type:int" json:"state"`
|
||||
}
|
||||
|
||||
// TableName return tableName "k8s_resources"
|
||||
func (k *K8sResource) TableName() string {
|
||||
return "k8s_resources"
|
||||
}
|
||||
|
64
db/model/component.go
Normal file
64
db/model/component.go
Normal file
@ -0,0 +1,64 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2022-2022 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
//K8sAttributeNameNodeSelector -
|
||||
K8sAttributeNameNodeSelector = "nodeSelector"
|
||||
//K8sAttributeNameLabels -
|
||||
K8sAttributeNameLabels = "labels"
|
||||
//K8sAttributeNameTolerations -
|
||||
K8sAttributeNameTolerations = "tolerations"
|
||||
//K8sAttributeNameVolumes -
|
||||
K8sAttributeNameVolumes = "volumes"
|
||||
//K8sAttributeNameServiceAccountName -
|
||||
K8sAttributeNameServiceAccountName = "serviceAccountName"
|
||||
//K8sAttributeNamePrivileged -
|
||||
K8sAttributeNamePrivileged = "privileged"
|
||||
//K8sAttributeNameAffinity -
|
||||
K8sAttributeNameAffinity = "affinity"
|
||||
//K8sAttributeNameVolumeMounts -
|
||||
K8sAttributeNameVolumeMounts = "volumeMounts"
|
||||
//K8sAttributeNameENV -
|
||||
K8sAttributeNameENV = "env"
|
||||
)
|
||||
|
||||
// ComponentK8sAttributes -
|
||||
type ComponentK8sAttributes struct {
|
||||
Model
|
||||
TenantID string `gorm:"column:tenant_id;size:32" validate:"tenant_id|between:30,33" json:"tenant_id"`
|
||||
ComponentID string `gorm:"column:component_id" json:"component_id"`
|
||||
|
||||
// Name Define the attribute name, which is currently supported
|
||||
// [nodeSelector/labels/tolerations/volumes/serviceAccountName/privileged/affinity/volumeMounts]
|
||||
// The field name should be the same as that in the K8s resource yaml file.
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
|
||||
// The field type defines how the attribute is stored. Currently, `json/yaml/string` are supported
|
||||
SaveType string `gorm:"column:save_type" json:"save_type"`
|
||||
|
||||
// Define the attribute value, which is stored in the database.
|
||||
// The value is stored in the database in the form of `json/yaml/string`.
|
||||
AttributeValue string `gorm:"column:attribute_value;type:longtext" json:"attribute_value"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (t *ComponentK8sAttributes) TableName() string {
|
||||
return "component_k8s_attributes"
|
||||
}
|
@ -107,6 +107,22 @@ func (s ServiceType) IsState() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsJob is job
|
||||
func (s ServiceType) IsJob() bool {
|
||||
if s == ServiceTypeJob {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCronJob is cronjob
|
||||
func (s ServiceType) IsCronJob() bool {
|
||||
if s == ServiceTypeCronJob {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSingleton is singleton or not
|
||||
func (s ServiceType) IsSingleton() bool {
|
||||
if s == "" {
|
||||
@ -127,6 +143,22 @@ func (t *TenantServices) IsState() bool {
|
||||
return ServiceType(t.ExtendMethod).IsState()
|
||||
}
|
||||
|
||||
// IsJob is job
|
||||
func (t *TenantServices) IsJob() bool {
|
||||
if ServiceType(t.ExtendMethod).IsJob() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCronJob is cronjob
|
||||
func (t *TenantServices) IsCronJob() bool {
|
||||
if ServiceType(t.ExtendMethod).IsCronJob() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSingleton is singleton or multiple service
|
||||
func (t *TenantServices) IsSingleton() bool {
|
||||
if t.ExtendMethod == "" {
|
||||
@ -150,6 +182,12 @@ var ServiceTypeStateSingleton ServiceType = "state_singleton"
|
||||
// ServiceTypeStateMultiple state_multiple
|
||||
var ServiceTypeStateMultiple ServiceType = "state_multiple"
|
||||
|
||||
// ServiceTypeJob job
|
||||
var ServiceTypeJob ServiceType = "job"
|
||||
|
||||
// ServiceTypeCronJob cronjob
|
||||
var ServiceTypeCronJob ServiceType = "cronjob"
|
||||
|
||||
//TenantServices app service base info
|
||||
type TenantServices struct {
|
||||
Model
|
||||
@ -203,6 +241,8 @@ type TenantServices struct {
|
||||
AppID string `gorm:"column:app_id" json:"app_id"`
|
||||
// Component name in cluster
|
||||
K8sComponentName string `gorm:"column:k8s_component_name" json:"k8s_component_name"`
|
||||
// Job任务策略
|
||||
JobStrategy string `gorm:"column:job_strategy" json:"job_strategy"`
|
||||
}
|
||||
|
||||
// ComponentWorkload -
|
||||
@ -324,6 +364,8 @@ type TenantServicesDelete struct {
|
||||
AppID string `gorm:"column:app_id" json:"app_id"`
|
||||
// Component name in cluster
|
||||
K8sComponentName string `gorm:"column:k8s_component_name" json:"k8s_component_name"`
|
||||
// Job任务策略
|
||||
JobStrategy string `gorm:"column:job_strategy" json:"job_strategy"`
|
||||
}
|
||||
|
||||
//TableName 表名
|
||||
|
@ -105,3 +105,15 @@ func (a *ApplicationDaoImpl) IsK8sAppDuplicate(tenantID, AppID, k8sApp string) b
|
||||
}
|
||||
return count > 0
|
||||
}
|
||||
|
||||
//GetAppByName -
|
||||
func (a *ApplicationDaoImpl) GetAppByName(tenantID, k8sAppName string) (*model.Application, error) {
|
||||
var app model.Application
|
||||
if err := a.DB.Where("tenant_id=? and k8s_app=?", tenantID, k8sAppName).Find(&app).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, bcode.ErrApplicationNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &app, nil
|
||||
}
|
||||
|
81
db/mysql/dao/k8s_resource.go
Normal file
81
db/mysql/dao/k8s_resource.go
Normal file
@ -0,0 +1,81 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2022-2022 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
gormbulkups "github.com/atcdot/gorm-bulk-upsert"
|
||||
"github.com/goodrain/rainbond/db/model"
|
||||
"github.com/jinzhu/gorm"
|
||||
pkgerr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// K8sResourceDaoImpl k8s resource dao
|
||||
type K8sResourceDaoImpl struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
// AddModel add model
|
||||
func (t *K8sResourceDaoImpl) AddModel(mo model.Interface) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateModel update model
|
||||
func (t *K8sResourceDaoImpl) UpdateModel(mo model.Interface) error {
|
||||
resource, ok := mo.(*model.K8sResource)
|
||||
if !ok {
|
||||
return fmt.Errorf("mo.(*model.K8sResource) err")
|
||||
}
|
||||
return t.DB.Save(resource).Error
|
||||
}
|
||||
|
||||
// ListByAppID list by app id
|
||||
func (t *K8sResourceDaoImpl) ListByAppID(appID string) ([]model.K8sResource, error) {
|
||||
var resources []model.K8sResource
|
||||
if err := t.DB.Where("app_id = ?", appID).Find(&resources).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
//CreateK8sResourceInBatch -
|
||||
func (t *K8sResourceDaoImpl) CreateK8sResourceInBatch(k8sResources []*model.K8sResource) error {
|
||||
var objects []interface{}
|
||||
for _, cg := range k8sResources {
|
||||
objects = append(objects, *cg)
|
||||
}
|
||||
if err := gormbulkups.BulkUpsert(t.DB, objects, 2000); err != nil {
|
||||
return pkgerr.Wrap(err, "create K8sResource groups in batch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//DeleteK8sResourceInBatch -
|
||||
func (t *K8sResourceDaoImpl) DeleteK8sResourceInBatch(appID, name string, kind string) error {
|
||||
return t.DB.Where("app_id=? and name=? and kind=?", appID, name, kind).Delete(&model.K8sResource{}).Error
|
||||
}
|
||||
|
||||
//GetK8sResourceByNameInBatch -
|
||||
func (t *K8sResourceDaoImpl) GetK8sResourceByNameInBatch(appID, name, kind string) ([]model.K8sResource, error) {
|
||||
var resources []model.K8sResource
|
||||
if err := t.DB.Where("app_id=? and name=? and kind=?", appID, name, kind).Find(&resources).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
@ -2019,3 +2019,55 @@ func (t *TenantServiceScalingRecordsDaoImpl) CountByServiceID(serviceID string)
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// ComponentK8sAttributeDaoImpl The K8s attribute value of the component
|
||||
type ComponentK8sAttributeDaoImpl struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
// AddModel -
|
||||
func (t *ComponentK8sAttributeDaoImpl) AddModel(mo model.Interface) error {
|
||||
attr := mo.(*model.ComponentK8sAttributes)
|
||||
var old model.ComponentK8sAttributes
|
||||
if ok := t.DB.Where("component_id=? and name=?", attr.ComponentID, attr.Name).Find(&old).RecordNotFound(); ok {
|
||||
return t.DB.Create(attr).Error
|
||||
}
|
||||
return errors.ErrRecordAlreadyExist
|
||||
}
|
||||
|
||||
// UpdateModel -
|
||||
func (t *ComponentK8sAttributeDaoImpl) UpdateModel(mo model.Interface) error {
|
||||
attr := mo.(*model.ComponentK8sAttributes)
|
||||
return t.DB.Save(attr).Error
|
||||
}
|
||||
|
||||
// GetByComponentIDAndName -
|
||||
func (t *ComponentK8sAttributeDaoImpl) GetByComponentIDAndName(componentID, name string) (*model.ComponentK8sAttributes, error) {
|
||||
var record model.ComponentK8sAttributes
|
||||
if err := t.DB.Where("component_id=? and name=?", componentID, name).Take(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateAttributesInBatch Batch insert or update component attributes
|
||||
func (t *ComponentK8sAttributeDaoImpl) CreateOrUpdateAttributesInBatch(attributes []*model.ComponentK8sAttributes) error {
|
||||
var objects []interface{}
|
||||
for _, attribute := range attributes {
|
||||
objects = append(objects, *attribute)
|
||||
}
|
||||
if err := gormbulkups.BulkUpsert(t.DB, objects, 2000); err != nil {
|
||||
return pkgerr.Wrap(err, "create or update component attributes in batch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteByComponentIDAndName delete by componentID and name
|
||||
func (t *ComponentK8sAttributeDaoImpl) DeleteByComponentIDAndName(componentID, name string) error {
|
||||
return t.DB.Where("component_id=? and name=?", componentID, name).Delete(&model.ComponentK8sAttributes{}).Error
|
||||
}
|
||||
|
||||
// DeleteByComponentIDs delete by componentIDs
|
||||
func (t *ComponentK8sAttributeDaoImpl) DeleteByComponentIDs(componentIDs []string) error {
|
||||
return t.DB.Where("component_id in (?)", componentIDs).Delete(&model.ComponentK8sAttributes{}).Error
|
||||
}
|
||||
|
@ -647,3 +647,31 @@ func (m *Manager) TenantServiceMonitorDaoTransactions(db *gorm.DB) dao.TenantSer
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// ComponentK8sAttributeDao -
|
||||
func (m *Manager) ComponentK8sAttributeDao() dao.ComponentK8sAttributeDao {
|
||||
return &mysqldao.ComponentK8sAttributeDaoImpl{
|
||||
DB: m.db,
|
||||
}
|
||||
}
|
||||
|
||||
// ComponentK8sAttributeDaoTransactions -
|
||||
func (m *Manager) ComponentK8sAttributeDaoTransactions(db *gorm.DB) dao.ComponentK8sAttributeDao {
|
||||
return &mysqldao.ComponentK8sAttributeDaoImpl{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// K8sResourceDao -
|
||||
func (m *Manager) K8sResourceDao() dao.K8sResourceDao {
|
||||
return &mysqldao.K8sResourceDaoImpl{
|
||||
DB: m.db,
|
||||
}
|
||||
}
|
||||
|
||||
// K8sResourceDaoTransactions -
|
||||
func (m *Manager) K8sResourceDaoTransactions(db *gorm.DB) dao.K8sResourceDao {
|
||||
return &mysqldao.K8sResourceDaoImpl{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,8 @@ func (m *Manager) RegisterTableModel() {
|
||||
m.models = append(m.models, &model.TenantServiceAutoscalerRuleMetrics{})
|
||||
m.models = append(m.models, &model.TenantServiceScalingRecords{})
|
||||
m.models = append(m.models, &model.TenantServiceMonitor{})
|
||||
m.models = append(m.models, &model.ComponentK8sAttributes{})
|
||||
m.models = append(m.models, &model.K8sResource{})
|
||||
}
|
||||
|
||||
//CheckTable check and create tables
|
||||
|
107
util/copydir.go
Normal file
107
util/copydir.go
Normal file
@ -0,0 +1,107 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FormatPath format path
|
||||
func FormatPath(s string) string {
|
||||
log.Println("runtime.GOOS:", runtime.GOOS)
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return strings.Replace(s, "/", "\\", -1)
|
||||
case "darwin", "linux":
|
||||
return strings.Replace(s, "\\", "/", -1)
|
||||
default:
|
||||
logrus.Info("only support linux,windows,darwin, but os is " + runtime.GOOS)
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// MoveDir move dir
|
||||
func MoveDir(src string, dest string) error {
|
||||
src = FormatPath(src)
|
||||
dest = FormatPath(dest)
|
||||
logrus.Info("src", src)
|
||||
logrus.Info("dest", dest)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = exec.Command("xcopy", src, dest, "/I", "/E")
|
||||
case "darwin", "linux":
|
||||
cmd = exec.Command("cp", "-R", src, dest)
|
||||
}
|
||||
outPut, err := cmd.Output()
|
||||
if err != nil {
|
||||
logrus.Errorf("Output error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
fmt.Println(outPut)
|
||||
if err := os.RemoveAll(src); err != nil {
|
||||
logrus.Errorf("remove oldpath error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MD5 md5
|
||||
func MD5(file string) string {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
_, err = io.Copy(h, f)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
res := hex.EncodeToString(h.Sum(nil))
|
||||
logrus.Info("md5:", res)
|
||||
return res
|
||||
}
|
||||
|
||||
// CopyDir move dir
|
||||
func CopyDir(src string, dest string) error {
|
||||
_, err := os.Stat(dest)
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
err := os.MkdirAll(dest, 0755)
|
||||
if err != nil {
|
||||
logrus.Error("make and copy dir error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
src = FormatPath(src)
|
||||
dest = FormatPath(dest)
|
||||
logrus.Info("src", src)
|
||||
logrus.Info("dest", dest)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = exec.Command("xcopy", src, dest, "/I", "/E")
|
||||
case "darwin", "linux":
|
||||
cmd = exec.Command("cp", "-R", src, dest)
|
||||
}
|
||||
outPut, err := cmd.Output()
|
||||
if err != nil {
|
||||
logrus.Errorf("Output error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
fmt.Println(outPut)
|
||||
return nil
|
||||
}
|
@ -130,7 +130,7 @@ func (s *startController) startOne(app v1.AppService) error {
|
||||
return fmt.Errorf("create claims: %v", err)
|
||||
}
|
||||
}
|
||||
//step 2: create statefulset or deployment
|
||||
//step 2: create statefulset or deployment or job or cronjob
|
||||
if statefulset := app.GetStatefulSet(); statefulset != nil {
|
||||
_, err = s.manager.client.AppsV1().StatefulSets(app.GetNamespace()).Create(s.ctx, statefulset, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
@ -143,6 +143,18 @@ func (s *startController) startOne(app v1.AppService) error {
|
||||
return fmt.Errorf("create deployment failure:%s;", err.Error())
|
||||
}
|
||||
}
|
||||
if job := app.GetJob(); job != nil {
|
||||
_, err = s.manager.client.BatchV1().Jobs(app.GetNamespace()).Create(s.ctx, job, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("create job failure:%s;", err.Error())
|
||||
}
|
||||
}
|
||||
if cronjob := app.GetCronJob(); cronjob != nil {
|
||||
_, err = s.manager.client.BatchV1beta1().CronJobs(app.GetNamespace()).Create(s.ctx, cronjob, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("create cronjob failure:%s;", err.Error())
|
||||
}
|
||||
}
|
||||
//step 3: create services
|
||||
if services := app.GetServices(true); services != nil {
|
||||
if err := CreateKubeService(s.manager.client, app.GetNamespace(), services...); err != nil {
|
||||
|
@ -162,6 +162,21 @@ func (s *stopController) stopOne(app v1.AppService) error {
|
||||
}
|
||||
s.manager.store.OnDeletes(deployment)
|
||||
}
|
||||
if job := app.GetJob(); job != nil {
|
||||
err := s.manager.client.BatchV1().Jobs(app.GetNamespace()).Delete(s.ctx, job.Name, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return fmt.Errorf("delete job failure:%s", err.Error())
|
||||
}
|
||||
s.manager.store.OnDeletes(job)
|
||||
}
|
||||
if cronjob := app.GetCronJob(); cronjob != nil {
|
||||
propagationPolicy := metav1.DeletePropagationBackground
|
||||
err := s.manager.client.BatchV1beta1().CronJobs(app.GetNamespace()).Delete(s.ctx, cronjob.Name, metav1.DeleteOptions{PropagationPolicy: &propagationPolicy})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return fmt.Errorf("delete cronjob failure:%s", err.Error())
|
||||
}
|
||||
s.manager.store.OnDeletes(cronjob)
|
||||
}
|
||||
//step 6: delete all pod
|
||||
var gracePeriodSeconds int64
|
||||
if pods := app.GetPods(true); pods != nil {
|
||||
|
@ -19,10 +19,17 @@
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
apimodel "github.com/goodrain/rainbond/api/model"
|
||||
|
||||
"github.com/goodrain/rainbond/api/handler/app_governance_mode/adaptor"
|
||||
"github.com/sirupsen/logrus"
|
||||
"strings"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
|
||||
"github.com/goodrain/rainbond/db"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
@ -130,6 +137,14 @@ func TenantServiceBase(as *v1.AppService, dbmanager db.Manager) error {
|
||||
as.ContainerGPU = tenantService.ContainerGPU
|
||||
as.ContainerMemory = tenantService.ContainerMemory
|
||||
as.Replicas = tenantService.Replicas
|
||||
if tenantService.IsJob() {
|
||||
initBaseJob(as, tenantService)
|
||||
return nil
|
||||
}
|
||||
if tenantService.IsCronJob() {
|
||||
initBaseCronJob(as, tenantService)
|
||||
return nil
|
||||
}
|
||||
if !tenantService.IsState() {
|
||||
initBaseDeployment(as, tenantService)
|
||||
return nil
|
||||
@ -216,6 +231,116 @@ func initBaseDeployment(as *v1.AppService, service *dbmodel.TenantServices) {
|
||||
as.SetDeployment(deployment)
|
||||
}
|
||||
|
||||
func initBaseJob(as *v1.AppService, service *dbmodel.TenantServices) {
|
||||
as.ServiceType = v1.TypeJob
|
||||
job := as.GetJob()
|
||||
if job == nil {
|
||||
job = &batchv1.Job{}
|
||||
}
|
||||
job.Namespace = as.GetNamespace()
|
||||
if job.Spec.Selector == nil {
|
||||
job.Spec.Selector = &metav1.LabelSelector{}
|
||||
}
|
||||
job.Name = as.GetK8sWorkloadName()
|
||||
job.GenerateName = strings.Replace(service.ServiceAlias, "_", "-", -1)
|
||||
injectLabels := getInjectLabels(as)
|
||||
job.Labels = as.GetCommonLabels(job.Labels, map[string]string{
|
||||
"name": service.ServiceAlias,
|
||||
"version": service.DeployVersion,
|
||||
}, injectLabels)
|
||||
|
||||
var js *apimodel.JobStrategy
|
||||
if service.JobStrategy != ""{
|
||||
err := json.Unmarshal([]byte(service.JobStrategy), &js)
|
||||
if err != nil {
|
||||
logrus.Error("job strategy json unmarshal error", err)
|
||||
}
|
||||
if js.ActiveDeadlineSeconds != "" {
|
||||
ads, err := strconv.ParseInt(js.ActiveDeadlineSeconds, 10, 64)
|
||||
if err == nil {
|
||||
job.Spec.ActiveDeadlineSeconds = &ads
|
||||
}
|
||||
}
|
||||
if js.BackoffLimit != "" {
|
||||
res, err := strconv.ParseInt(js.BackoffLimit, 10, 32)
|
||||
if err == nil {
|
||||
bkl := int32(res)
|
||||
job.Spec.BackoffLimit = &bkl
|
||||
}
|
||||
}
|
||||
if js.Parallelism != "" {
|
||||
res, err := strconv.ParseInt(js.Parallelism, 10, 32)
|
||||
if err == nil {
|
||||
pll := int32(res)
|
||||
job.Spec.Parallelism = &pll
|
||||
}
|
||||
}
|
||||
if js.Completions != "" {
|
||||
res, err := strconv.ParseInt(js.Completions, 10, 32)
|
||||
if err == nil {
|
||||
cpt := int32(res)
|
||||
job.Spec.Completions = &cpt
|
||||
}
|
||||
}
|
||||
}
|
||||
as.SetJob(job)
|
||||
}
|
||||
|
||||
func initBaseCronJob(as *v1.AppService, service *dbmodel.TenantServices) {
|
||||
as.ServiceType = v1.TypeCronJob
|
||||
cronJob := as.GetCronJob()
|
||||
if cronJob == nil {
|
||||
cronJob = &v1beta1.CronJob{}
|
||||
}
|
||||
injectLabels := getInjectLabels(as)
|
||||
jobTemp := v1beta1.JobTemplateSpec{}
|
||||
jobTemp.Name = as.GetK8sWorkloadName()
|
||||
jobTemp.Namespace = as.GetNamespace()
|
||||
jobTemp.Labels = as.GetCommonLabels(jobTemp.Labels, map[string]string{
|
||||
"name": service.ServiceAlias,
|
||||
"version": service.DeployVersion,
|
||||
}, injectLabels)
|
||||
if service.JobStrategy != ""{
|
||||
var js *apimodel.JobStrategy
|
||||
err := json.Unmarshal([]byte(service.JobStrategy), &js)
|
||||
if err != nil {
|
||||
logrus.Error("job strategy json unmarshal error", err)
|
||||
}
|
||||
if js.ActiveDeadlineSeconds != "" {
|
||||
ads, err := strconv.ParseInt(js.ActiveDeadlineSeconds, 10, 64)
|
||||
if err == nil {
|
||||
jobTemp.Spec.ActiveDeadlineSeconds = &ads
|
||||
}
|
||||
}
|
||||
if js.BackoffLimit != "" {
|
||||
res, err := strconv.ParseInt(js.BackoffLimit, 10, 32)
|
||||
if err == nil {
|
||||
bkl := int32(res)
|
||||
jobTemp.Spec.BackoffLimit = &bkl
|
||||
}
|
||||
}
|
||||
if js.Parallelism != "" {
|
||||
res, err := strconv.ParseInt(js.Parallelism, 10, 32)
|
||||
if err == nil {
|
||||
pll := int32(res)
|
||||
jobTemp.Spec.Parallelism = &pll
|
||||
}
|
||||
}
|
||||
if js.Completions != "" {
|
||||
res, err := strconv.ParseInt(js.Completions, 10, 32)
|
||||
if err == nil {
|
||||
cpt := int32(res)
|
||||
jobTemp.Spec.Completions = &cpt
|
||||
}
|
||||
}
|
||||
cronJob.Spec.Schedule = js.Schedule
|
||||
}
|
||||
cronJob.Spec.JobTemplate = jobTemp
|
||||
cronJob.Namespace = as.GetNamespace()
|
||||
cronJob.Name = as.GetK8sWorkloadName()
|
||||
as.SetCronJob(cronJob)
|
||||
}
|
||||
|
||||
func getInjectLabels(as *v1.AppService) map[string]string {
|
||||
mode, err := adaptor.NewAppGoveranceModeHandler(as.GovernanceMode, nil)
|
||||
if err != nil {
|
||||
|
@ -19,14 +19,16 @@
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/builder/sources"
|
||||
"net"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goodrain/rainbond/builder/sources"
|
||||
|
||||
"github.com/goodrain/rainbond/builder"
|
||||
"github.com/goodrain/rainbond/db"
|
||||
"github.com/goodrain/rainbond/db/model"
|
||||
@ -41,6 +43,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
//TenantServiceVersion service deploy version conv. define pod spec
|
||||
@ -70,20 +73,18 @@ func TenantServiceVersion(as *v1.AppService, dbmanager db.Manager) error {
|
||||
dv.SetVolume(dbmodel.ShareFileVolumeType, "kube-config", "/etc/kubernetes", "/grdata/kubernetes", corev1.HostPathDirectoryOrCreate, true)
|
||||
}
|
||||
nodeSelector := createNodeSelector(as, dbmanager)
|
||||
tolerations := createToleration(nodeSelector)
|
||||
injectLabels := getInjectLabels(as)
|
||||
labels := createLabels(as, dbmanager)
|
||||
tolerations := createToleration(nodeSelector, as, dbmanager)
|
||||
volumes := getVolumes(dv, as, dbmanager)
|
||||
podtmpSpec := corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: as.GetCommonLabels(map[string]string{
|
||||
"name": as.ServiceAlias,
|
||||
"version": as.DeployVersion,
|
||||
}, injectLabels),
|
||||
Labels: labels,
|
||||
Annotations: createPodAnnotations(as),
|
||||
Name: as.GetK8sWorkloadName() + "-pod-spec",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
ImagePullSecrets: setImagePullSecrets(),
|
||||
Volumes: dv.GetVolumes(),
|
||||
Volumes: volumes,
|
||||
Containers: []corev1.Container{*container},
|
||||
NodeSelector: nodeSelector,
|
||||
Tolerations: tolerations,
|
||||
@ -113,13 +114,20 @@ func TenantServiceVersion(as *v1.AppService, dbmanager db.Manager) error {
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
ServiceAccountName: createServiceAccountName(as, dbmanager),
|
||||
},
|
||||
}
|
||||
var terminationGracePeriodSeconds int64 = 10
|
||||
if as.GetDeployment() != nil {
|
||||
podtmpSpec.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
||||
}
|
||||
//set to deployment or statefulset
|
||||
if as.GetJob() != nil {
|
||||
podtmpSpec.Spec.RestartPolicy = "Never"
|
||||
}
|
||||
if as.GetCronJob() != nil {
|
||||
podtmpSpec.Spec.RestartPolicy = "OnFailure"
|
||||
}
|
||||
//set to deployment or statefulset job or cronjob
|
||||
as.SetPodTemplate(podtmpSpec)
|
||||
return nil
|
||||
}
|
||||
@ -158,7 +166,7 @@ func getMainContainer(as *v1.AppService, version *dbmodel.VersionInfo, dv *volum
|
||||
Ports: ports,
|
||||
Env: envs,
|
||||
EnvFrom: envFromSecrets,
|
||||
VolumeMounts: dv.GetVolumeMounts(),
|
||||
VolumeMounts: createVolumeMounts(dv, as, dbmanager),
|
||||
LivenessProbe: createProbe(as, dbmanager, "liveness"),
|
||||
ReadinessProbe: createProbe(as, dbmanager, "readiness"),
|
||||
Resources: resources,
|
||||
@ -172,6 +180,17 @@ func getMainContainer(as *v1.AppService, version *dbmodel.VersionInfo, dv *volum
|
||||
logrus.Infof("service id: %s; enable privileged.", as.ServiceID)
|
||||
c.SecurityContext = &corev1.SecurityContext{Privileged: util.Bool(true)}
|
||||
}
|
||||
privilegedAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNamePrivileged)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("get by privileged attribute error: %v", err)
|
||||
}
|
||||
if privilegedAttribute != nil {
|
||||
pril, err := strconv.ParseBool(privilegedAttribute.AttributeValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.SecurityContext = &corev1.SecurityContext{Privileged: util.Bool(pril)}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@ -364,6 +383,23 @@ func createEnv(as *v1.AppService, dbmanager db.Manager, envVarSecrets []*corev1.
|
||||
as.ExtensionSet[strings.ToLower(k[3:])] = v
|
||||
}
|
||||
}
|
||||
var customEnvs []corev1.EnvVar
|
||||
envAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameENV)
|
||||
if err != nil {
|
||||
logrus.Warn("get by env attribute error", err)
|
||||
return envs, nil
|
||||
}
|
||||
envAttributeJSON, err := yaml.YAMLToJSON([]byte(envAttribute.AttributeValue))
|
||||
if err != nil {
|
||||
logrus.Warn("envAttribute yaml to json error", err)
|
||||
return envs, nil
|
||||
}
|
||||
err = json.Unmarshal(envAttributeJSON, &customEnvs)
|
||||
if err != nil {
|
||||
logrus.Warn("envAttribute json unmarshal error", err)
|
||||
return envs, nil
|
||||
}
|
||||
envs = append(envs, customEnvs...)
|
||||
return envs, nil
|
||||
}
|
||||
|
||||
@ -494,6 +530,28 @@ func createVolumes(as *v1.AppService, version *dbmodel.VersionInfo, envs []corev
|
||||
return define, nil
|
||||
}
|
||||
|
||||
func getVolumes(dv *volume.Define, as *v1.AppService, dbmanager db.Manager) []corev1.Volume {
|
||||
volumes := dv.GetVolumes()
|
||||
volumeAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameVolumes)
|
||||
if err != nil {
|
||||
logrus.Warn("get by volumes attribute error", err)
|
||||
return volumes
|
||||
}
|
||||
var vs []corev1.Volume
|
||||
VolumeAttributeJSON, err := yaml.YAMLToJSON([]byte(volumeAttribute.AttributeValue))
|
||||
if err != nil {
|
||||
logrus.Warn("volumeAttribute yaml to json error", err)
|
||||
return volumes
|
||||
}
|
||||
err = json.Unmarshal(VolumeAttributeJSON, &vs)
|
||||
if err != nil {
|
||||
logrus.Warn("volumeAttribute json unmarshal error", err)
|
||||
return volumes
|
||||
}
|
||||
volumes = append(volumes, vs...)
|
||||
return volumes
|
||||
}
|
||||
|
||||
func createResources(as *v1.AppService) corev1.ResourceRequirements {
|
||||
var cpuRequest, cpuLimit int64
|
||||
if limit, ok := as.ExtensionSet["cpulimit"]; ok {
|
||||
@ -661,8 +719,36 @@ func createNodeSelector(as *v1.AppService, dbmanager db.Manager) map[string]stri
|
||||
}
|
||||
}
|
||||
}
|
||||
selectorAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameNodeSelector)
|
||||
if err != nil {
|
||||
logrus.Warn("get by NodeSelector attribute error", err)
|
||||
return selector
|
||||
}
|
||||
err = json.Unmarshal([]byte(selectorAttribute.AttributeValue), &selector)
|
||||
if err != nil {
|
||||
logrus.Warn("selector json unmarshal error", err)
|
||||
return selector
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
func createLabels(as *v1.AppService, dbmanager db.Manager) map[string]string {
|
||||
labels := make(map[string]string)
|
||||
labelsAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameLabels)
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(labelsAttribute.AttributeValue), &labels)
|
||||
if err == nil{
|
||||
logrus.Infof("labelsAttribute:%s", labels)
|
||||
}
|
||||
}
|
||||
labels["name"] = as.ServiceAlias
|
||||
labels["version"] = as.DeployVersion
|
||||
injectLabels := getInjectLabels(as)
|
||||
resultLabel := as.GetCommonLabels(labels, injectLabels)
|
||||
return resultLabel
|
||||
}
|
||||
|
||||
|
||||
func createAffinity(as *v1.AppService, dbmanager db.Manager) *corev1.Affinity {
|
||||
var affinity corev1.Affinity
|
||||
nsr := make([]corev1.NodeSelectorRequirement, 0)
|
||||
@ -769,6 +855,21 @@ func createAffinity(as *v1.AppService, dbmanager db.Manager) *corev1.Affinity {
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: podAntAffinity,
|
||||
}
|
||||
}
|
||||
affinityAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameAffinity)
|
||||
if err != nil {
|
||||
logrus.Warn("get by affinity attribute error", err)
|
||||
return &affinity
|
||||
}
|
||||
AffinityAttributeJSON, err := yaml.YAMLToJSON([]byte(affinityAttribute.AttributeValue))
|
||||
if err != nil {
|
||||
logrus.Warn("Affinity attribute yaml to json error", err)
|
||||
return &affinity
|
||||
}
|
||||
err = json.Unmarshal(AffinityAttributeJSON, &affinity)
|
||||
if err != nil {
|
||||
logrus.Warn("affinity json unmarshal error", err)
|
||||
return &affinity
|
||||
}
|
||||
return &affinity
|
||||
}
|
||||
|
||||
@ -795,7 +896,7 @@ func setImagePullSecrets() []corev1.LocalObjectReference {
|
||||
}
|
||||
}
|
||||
|
||||
func createToleration(nodeSelector map[string]string) []corev1.Toleration {
|
||||
func createToleration(nodeSelector map[string]string, as *v1.AppService, dbmanager db.Manager) []corev1.Toleration {
|
||||
var tolerations []corev1.Toleration
|
||||
if value, exist := nodeSelector["type"]; exist && value == "virtual-kubelet" {
|
||||
tolerations = append(tolerations, corev1.Toleration{
|
||||
@ -803,6 +904,24 @@ func createToleration(nodeSelector map[string]string) []corev1.Toleration {
|
||||
Operator: corev1.TolerationOpExists,
|
||||
})
|
||||
}
|
||||
tolerationAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameTolerations)
|
||||
if err != nil {
|
||||
logrus.Warn("get by toleration attribute error", err)
|
||||
return tolerations
|
||||
}
|
||||
var tolers []corev1.Toleration
|
||||
tolerationAttributeJSON, err := yaml.YAMLToJSON([]byte(tolerationAttribute.AttributeValue))
|
||||
if err != nil {
|
||||
logrus.Warn("toleration attribute yaml to json error", err)
|
||||
return tolerations
|
||||
}
|
||||
err = json.Unmarshal(tolerationAttributeJSON, &tolers)
|
||||
if err != nil {
|
||||
logrus.Warn("toleration json unmarshal error", err)
|
||||
return tolerations
|
||||
}
|
||||
tolerations = append(tolerations, tolers...)
|
||||
|
||||
return tolerations
|
||||
}
|
||||
|
||||
@ -825,3 +944,37 @@ func createHostAliases(as *v1.AppService) []corev1.HostAlias {
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
func createServiceAccountName(as *v1.AppService, dbmanager db.Manager) string {
|
||||
var serviceAN string
|
||||
sa, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameServiceAccountName)
|
||||
if err != nil {
|
||||
logrus.Warn("get by ServiceAccountName attribute error", err)
|
||||
return ""
|
||||
}
|
||||
serviceAN = sa.AttributeValue
|
||||
return serviceAN
|
||||
}
|
||||
|
||||
func createVolumeMounts(dv *volume.Define, as *v1.AppService, dbmanager db.Manager) []corev1.VolumeMount {
|
||||
volumeMounts := dv.GetVolumeMounts()
|
||||
volumeMountsAttribute, err := dbmanager.ComponentK8sAttributeDao().GetByComponentIDAndName(as.ServiceID, model.K8sAttributeNameVolumeMounts)
|
||||
if err != nil {
|
||||
logrus.Warn("get by volumeMounts attribute error", err)
|
||||
return volumeMounts
|
||||
}
|
||||
|
||||
var vms []corev1.VolumeMount
|
||||
VolumeMountsAttributeJSON, err := yaml.YAMLToJSON([]byte(volumeMountsAttribute.AttributeValue))
|
||||
if err != nil {
|
||||
logrus.Warn("volumeMounts attribute yaml to json error", err)
|
||||
return volumeMounts
|
||||
}
|
||||
err = json.Unmarshal(VolumeMountsAttributeJSON, &vms)
|
||||
if err != nil {
|
||||
logrus.Warn("volumeMounts json unmarshal error", err)
|
||||
return volumeMounts
|
||||
}
|
||||
volumeMounts = append(volumeMounts, vms...)
|
||||
return volumeMounts
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ type Informer struct {
|
||||
HelmApp cache.SharedIndexInformer
|
||||
ComponentDefinition cache.SharedIndexInformer
|
||||
ThirdComponent cache.SharedIndexInformer
|
||||
Job cache.SharedIndexInformer
|
||||
CronJob cache.SharedIndexInformer
|
||||
CRS map[string]cache.SharedIndexInformer
|
||||
}
|
||||
|
||||
@ -74,12 +76,14 @@ func (i *Informer) Start(stop chan struct{}) {
|
||||
go i.HelmApp.Run(stop)
|
||||
go i.ComponentDefinition.Run(stop)
|
||||
go i.ThirdComponent.Run(stop)
|
||||
go i.Job.Run(stop)
|
||||
go i.CronJob.Run(stop)
|
||||
}
|
||||
|
||||
//Ready if all kube informers is syncd, store is ready
|
||||
func (i *Informer) Ready() bool {
|
||||
if i.Namespace.HasSynced() && i.Ingress.HasSynced() && i.Service.HasSynced() && i.Secret.HasSynced() &&
|
||||
i.StatefulSet.HasSynced() && i.Deployment.HasSynced() && i.Pod.HasSynced() &&
|
||||
i.StatefulSet.HasSynced() && i.Deployment.HasSynced() && i.Pod.HasSynced() && i.Pod.HasSynced() && i.CronJob.HasSynced() &&
|
||||
i.ConfigMap.HasSynced() && i.Nodes.HasSynced() && i.Events.HasSynced() &&
|
||||
i.HorizontalPodAutoscaler.HasSynced() && i.StorageClass.HasSynced() && i.Claims.HasSynced() && i.CRD.HasSynced() {
|
||||
return true
|
||||
|
@ -23,9 +23,11 @@ import (
|
||||
crdlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1"
|
||||
appsv1 "k8s.io/client-go/listers/apps/v1"
|
||||
autoscalingv2 "k8s.io/client-go/listers/autoscaling/v2beta2"
|
||||
v1 "k8s.io/client-go/listers/batch/v1"
|
||||
v1beta1 "k8s.io/client-go/listers/batch/v1beta1"
|
||||
corev1 "k8s.io/client-go/listers/core/v1"
|
||||
betav1 "k8s.io/client-go/listers/networking/v1beta1"
|
||||
networkingv1 "k8s.io/client-go/listers/networking/v1"
|
||||
betav1 "k8s.io/client-go/listers/networking/v1beta1"
|
||||
storagev1 "k8s.io/client-go/listers/storage/v1"
|
||||
)
|
||||
|
||||
@ -49,4 +51,6 @@ type Lister struct {
|
||||
HelmApp v1alpha1.HelmAppLister
|
||||
ComponentDefinition v1alpha1.ComponentDefinitionLister
|
||||
ThirdComponent v1alpha1.ThirdComponentLister
|
||||
Job v1.JobLister
|
||||
CronJob v1beta1.CronJobLister
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
betav1 "k8s.io/api/networking/v1beta1"
|
||||
"os"
|
||||
"sync"
|
||||
@ -206,7 +208,6 @@ func NewStore(
|
||||
|
||||
store.informers.ConfigMap = infFactory.Core().V1().ConfigMaps().Informer()
|
||||
store.listers.ConfigMap = infFactory.Core().V1().ConfigMaps().Lister()
|
||||
|
||||
if k8sutil.IsHighVersion() {
|
||||
store.informers.Ingress = infFactory.Networking().V1().Ingresses().Informer()
|
||||
store.listers.Ingress = infFactory.Networking().V1().Ingresses().Lister()
|
||||
@ -245,7 +246,10 @@ func NewStore(
|
||||
store.listers.ComponentDefinition = rainbondInformer.Rainbond().V1alpha1().ComponentDefinitions().Lister()
|
||||
store.informers.ComponentDefinition = rainbondInformer.Rainbond().V1alpha1().ComponentDefinitions().Informer()
|
||||
store.informers.ComponentDefinition.AddEventHandlerWithResyncPeriod(componentdefinition.GetComponentDefinitionBuilder(), time.Second*300)
|
||||
|
||||
store.informers.Job = infFactory.Batch().V1().Jobs().Informer()
|
||||
store.listers.Job = infFactory.Batch().V1().Jobs().Lister()
|
||||
store.informers.CronJob = infFactory.Batch().V1beta1().CronJobs().Informer()
|
||||
store.listers.CronJob = infFactory.Batch().V1beta1().CronJobs().Lister()
|
||||
// Endpoint Event Handler
|
||||
epEventHandler := cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
@ -301,6 +305,8 @@ func NewStore(
|
||||
store.informers.Namespace.AddEventHandler(store.nsEventHandler())
|
||||
store.informers.Deployment.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
store.informers.StatefulSet.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
store.informers.Job.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
store.informers.CronJob.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
store.informers.Pod.AddEventHandlerWithResyncPeriod(store.podEventHandler(), time.Second*10)
|
||||
store.informers.Secret.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
store.informers.Service.AddEventHandlerWithResyncPeriod(store, time.Second*10)
|
||||
@ -400,6 +406,7 @@ func (a *appRuntimeStore) OnAdd(obj interface{}) {
|
||||
serviceID := deployment.Labels["service_id"]
|
||||
version := deployment.Labels["version"]
|
||||
createrID := deployment.Labels["creater_id"]
|
||||
migrator := deployment.Labels["migrator"]
|
||||
if serviceID != "" && version != "" && createrID != "" {
|
||||
appservice, err := a.getAppService(serviceID, version, createrID, true)
|
||||
if err == conversion.ErrServiceNotFound {
|
||||
@ -407,14 +414,84 @@ func (a *appRuntimeStore) OnAdd(obj interface{}) {
|
||||
}
|
||||
if appservice != nil {
|
||||
appservice.SetDeployment(deployment)
|
||||
if migrator == "rainbond" {
|
||||
label := "service_id=" + serviceID
|
||||
pods, _ := a.conf.KubeClient.CoreV1().Pods(deployment.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
|
||||
if pods != nil {
|
||||
for _, pod := range pods.Items {
|
||||
pod := pod
|
||||
appservice.SetPods(&pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if job, ok := obj.(*batchv1.Job); ok {
|
||||
serviceID := job.Labels["service_id"]
|
||||
version := job.Labels["version"]
|
||||
createrID := job.Labels["creater_id"]
|
||||
migrator := job.Labels["migrator"]
|
||||
if serviceID != "" && version != "" && createrID != "" {
|
||||
appservice, err := a.getAppService(serviceID, version, createrID, true)
|
||||
if err == conversion.ErrServiceNotFound {
|
||||
a.conf.KubeClient.BatchV1().Jobs(job.Namespace).Delete(context.Background(), job.Name, metav1.DeleteOptions{})
|
||||
}
|
||||
if appservice != nil {
|
||||
appservice.SetJob(job)
|
||||
if migrator == "rainbond" {
|
||||
label := "controller-uid=" + job.Spec.Selector.MatchLabels["controller-uid"]
|
||||
pods, _ := a.conf.KubeClient.CoreV1().Pods(job.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
|
||||
if pods != nil {
|
||||
for _, pod := range pods.Items {
|
||||
pod := pod
|
||||
appservice.SetPods(&pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if cjob, ok := obj.(*v1beta1.CronJob); ok {
|
||||
serviceID := cjob.Labels["service_id"]
|
||||
version := cjob.Labels["version"]
|
||||
createrID := cjob.Labels["creater_id"]
|
||||
migrator := cjob.Labels["migrator"]
|
||||
if serviceID != "" && version != "" && createrID != "" {
|
||||
appservice, err := a.getAppService(serviceID, version, createrID, true)
|
||||
if err == conversion.ErrServiceNotFound {
|
||||
a.conf.KubeClient.BatchV1beta1().CronJobs(cjob.Namespace).Delete(context.Background(), cjob.Name, metav1.DeleteOptions{})
|
||||
}
|
||||
if appservice != nil {
|
||||
appservice.SetCronJob(cjob)
|
||||
if migrator == "rainbond" {
|
||||
label := "service_id=" + serviceID
|
||||
jobList, _ := a.conf.KubeClient.BatchV1().Jobs(cjob.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
|
||||
for _, job := range jobList.Items {
|
||||
label := "controller-uid=" + job.Spec.Selector.MatchLabels["controller-uid"]
|
||||
pods, _ := a.conf.KubeClient.CoreV1().Pods(cjob.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
|
||||
if pods != nil {
|
||||
for _, pod := range pods.Items {
|
||||
pod := pod
|
||||
appservice.SetPods(&pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if statefulset, ok := obj.(*appsv1.StatefulSet); ok {
|
||||
serviceID := statefulset.Labels["service_id"]
|
||||
version := statefulset.Labels["version"]
|
||||
createrID := statefulset.Labels["creater_id"]
|
||||
migrator := statefulset.Labels["migrator"]
|
||||
if serviceID != "" && version != "" && createrID != "" {
|
||||
appservice, err := a.getAppService(serviceID, version, createrID, true)
|
||||
if err == conversion.ErrServiceNotFound {
|
||||
@ -422,6 +499,16 @@ func (a *appRuntimeStore) OnAdd(obj interface{}) {
|
||||
}
|
||||
if appservice != nil {
|
||||
appservice.SetStatefulSet(statefulset)
|
||||
if migrator == "rainbond" {
|
||||
label := "service_id=" + serviceID
|
||||
pods, _ := a.conf.KubeClient.CoreV1().Pods(statefulset.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
|
||||
if pods != nil {
|
||||
for _, pod := range pods.Items {
|
||||
pod := pod
|
||||
appservice.SetPods(&pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -517,6 +604,7 @@ func (a *appRuntimeStore) OnAdd(obj interface{}) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hpa, ok := obj.(*autoscalingv2.HorizontalPodAutoscaler); ok {
|
||||
serviceID := hpa.Labels["service_id"]
|
||||
version := hpa.Labels["version"]
|
||||
@ -862,6 +950,24 @@ func (a *appRuntimeStore) UpdateGetAppService(serviceID string) *v1.AppService {
|
||||
appService.SetDeployment(deploy)
|
||||
}
|
||||
}
|
||||
if job := appService.GetJob(); job != nil {
|
||||
j, err := a.listers.Job.Jobs(job.Namespace).Get(job.Name)
|
||||
if err != nil && k8sErrors.IsNotFound(err) {
|
||||
appService.DeleteJob(job)
|
||||
}
|
||||
if j != nil {
|
||||
appService.SetJob(j)
|
||||
}
|
||||
}
|
||||
if cronjob := appService.GetCronJob(); cronjob != nil {
|
||||
crjob, err := a.listers.CronJob.CronJobs(cronjob.Namespace).Get(cronjob.Name)
|
||||
if err != nil && k8sErrors.IsNotFound(err) {
|
||||
appService.DeleteCronJob(cronjob)
|
||||
}
|
||||
if crjob != nil {
|
||||
appService.SetCronJob(crjob)
|
||||
}
|
||||
}
|
||||
if services := appService.GetServices(true); services != nil {
|
||||
for _, service := range services {
|
||||
se, err := a.listers.Service.Services(service.Namespace).Get(service.Name)
|
||||
@ -1387,6 +1493,22 @@ func (a *appRuntimeStore) scalingRecordServiceAndRuleID(evt *corev1.Event) (stri
|
||||
}
|
||||
serviceID = deploy.GetLabels()["service_id"]
|
||||
ruleID = deploy.GetLabels()["rule_id"]
|
||||
case "Job":
|
||||
job, err := a.listers.Job.Jobs(evt.InvolvedObject.Namespace).Get(evt.InvolvedObject.Name)
|
||||
if err != nil {
|
||||
logrus.Warningf("retrieve job: %v", err)
|
||||
return "", ""
|
||||
}
|
||||
serviceID = job.GetLabels()["service_id"]
|
||||
ruleID = job.GetLabels()["rule_id"]
|
||||
case "CronJob":
|
||||
cjob, err := a.listers.CronJob.CronJobs(evt.InvolvedObject.Namespace).Get(evt.InvolvedObject.Name)
|
||||
if err != nil {
|
||||
logrus.Warningf("retrieve cronjob: %v", err)
|
||||
return "", ""
|
||||
}
|
||||
serviceID = cjob.GetLabels()["service_id"]
|
||||
ruleID = cjob.GetLabels()["rule_id"]
|
||||
case "Statefulset":
|
||||
statefulset, err := a.listers.StatefulSet.StatefulSets(evt.InvolvedObject.Namespace).Get(evt.InvolvedObject.Name)
|
||||
if err != nil {
|
||||
|
@ -210,6 +210,7 @@ func getStatefulsetAllowFields(s *v1.StatefulSet) *v1.StatefulSet {
|
||||
},
|
||||
UpdateStrategy: s.Spec.UpdateStrategy,
|
||||
},
|
||||
ObjectMeta: s.Spec.Template.ObjectMeta,
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,6 +242,7 @@ func getDeploymentAllowFields(d *v1.Deployment) *v1.Deployment {
|
||||
HostNetwork: d.Spec.Template.Spec.HostNetwork,
|
||||
SchedulerName: d.Spec.Template.Spec.SchedulerName,
|
||||
},
|
||||
ObjectMeta: d.Spec.Template.ObjectMeta,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
|
||||
//IsPodTerminated Exception evicted pod
|
||||
func IsPodTerminated(pod *corev1.Pod) bool {
|
||||
if phase := pod.Status.Phase; phase != corev1.PodPending && phase != corev1.PodRunning && phase != corev1.PodUnknown {
|
||||
if phase := pod.Status.Phase; phase != corev1.PodPending && phase != corev1.PodRunning && phase != corev1.PodUnknown && phase != corev1.PodSucceeded && phase != corev1.PodFailed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -93,6 +93,8 @@ var (
|
||||
BUILDEFAILURE = "build_failure"
|
||||
//UNDEPLOY init status
|
||||
UNDEPLOY = "undeploy"
|
||||
//SUCCEEDED if job and cronjob is succeeded
|
||||
SUCCEEDED = "succeeded"
|
||||
)
|
||||
|
||||
func conversionThirdComponent(obj runtime.Object) *v1alpha1.ThirdComponent {
|
||||
@ -158,6 +160,44 @@ func (a *AppService) GetServiceStatus() string {
|
||||
if a.IsClosed() {
|
||||
return CLOSED
|
||||
}
|
||||
if a.job != nil {
|
||||
succeed := 0
|
||||
failed := 0
|
||||
for _, po := range a.pods {
|
||||
if po.Status.Phase == "Succeeded" {
|
||||
succeed++
|
||||
}
|
||||
if po.Status.Phase == "Failed" {
|
||||
failed++
|
||||
}
|
||||
}
|
||||
if len(a.pods) == succeed {
|
||||
return SUCCEEDED
|
||||
}
|
||||
if failed > 0 {
|
||||
return ABNORMAL
|
||||
}
|
||||
return RUNNING
|
||||
}
|
||||
if a.cronjob != nil {
|
||||
succeed := 0
|
||||
failed := 0
|
||||
for _, po := range a.pods {
|
||||
if po.Status.Phase == "Succeeded" {
|
||||
succeed++
|
||||
}
|
||||
if po.Status.Phase == "Failed" {
|
||||
failed++
|
||||
}
|
||||
}
|
||||
if len(a.pods) == succeed {
|
||||
return RUNNING
|
||||
}
|
||||
if failed > 0 {
|
||||
return ABNORMAL
|
||||
}
|
||||
return RUNNING
|
||||
}
|
||||
if a.statefulset == nil && a.deployment == nil && len(a.pods) > 0 {
|
||||
return STOPPING
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goodrain/rainbond/util/k8s"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goodrain/rainbond/util/k8s"
|
||||
betav1 "k8s.io/api/networking/v1beta1"
|
||||
|
||||
"github.com/goodrain/rainbond/builder"
|
||||
"github.com/goodrain/rainbond/db/model"
|
||||
dbmodel "github.com/goodrain/rainbond/db/model"
|
||||
@ -33,9 +35,10 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
betav1 "k8s.io/api/networking/v1beta1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -71,6 +74,12 @@ var TypeStatefulSet AppServiceType = "statefulset"
|
||||
//TypeDeployment deployment
|
||||
var TypeDeployment AppServiceType = "deployment"
|
||||
|
||||
//TypeJob deployment
|
||||
var TypeJob AppServiceType = "job"
|
||||
|
||||
//TypeCronJob deployment
|
||||
var TypeCronJob AppServiceType = "cronjob"
|
||||
|
||||
//TypeReplicationController rc
|
||||
var TypeReplicationController AppServiceType = "replicationcontroller"
|
||||
|
||||
@ -153,6 +162,8 @@ type AppService struct {
|
||||
tenant *corev1.Namespace
|
||||
statefulset *v1.StatefulSet
|
||||
deployment *v1.Deployment
|
||||
job *batchv1.Job
|
||||
cronjob *v1beta1.CronJob
|
||||
workload runtime.Object
|
||||
hpas []*autoscalingv2.HorizontalPodAutoscaler
|
||||
delHPAs []*autoscalingv2.HorizontalPodAutoscaler
|
||||
@ -218,6 +229,16 @@ func (a *AppService) DeleteDeployment(d *v1.Deployment) {
|
||||
a.deployment = nil
|
||||
}
|
||||
|
||||
//DeleteJob delete kubernetes job model
|
||||
func (a *AppService) DeleteJob(d *batchv1.Job) {
|
||||
a.job = nil
|
||||
}
|
||||
|
||||
//DeleteCronJob delete kubernetes cronjob model
|
||||
func (a *AppService) DeleteCronJob(d *v1beta1.CronJob) {
|
||||
a.cronjob = nil
|
||||
}
|
||||
|
||||
//GetStatefulSet get kubernetes statefulset model
|
||||
func (a AppService) GetStatefulSet() *v1.StatefulSet {
|
||||
return a.statefulset
|
||||
@ -234,6 +255,36 @@ func (a *AppService) SetStatefulSet(d *v1.StatefulSet) {
|
||||
a.calculateComponentMemoryRequest()
|
||||
}
|
||||
|
||||
//GetJob get kubernetes job model
|
||||
func (a AppService) GetJob() *batchv1.Job {
|
||||
return a.job
|
||||
}
|
||||
|
||||
//SetJob set kubernetes job model
|
||||
func (a *AppService) SetJob(d *batchv1.Job) {
|
||||
a.job = d
|
||||
a.workload = d
|
||||
if v, ok := d.Spec.Template.Labels["version"]; ok && v != "" {
|
||||
a.DeployVersion = v
|
||||
}
|
||||
a.calculateComponentMemoryRequest()
|
||||
}
|
||||
|
||||
//GetCronJob get kubernetes cronjob model
|
||||
func (a AppService) GetCronJob() *v1beta1.CronJob {
|
||||
return a.cronjob
|
||||
}
|
||||
|
||||
//SetCronJob set kubernetes cronjob model
|
||||
func (a *AppService) SetCronJob(d *v1beta1.CronJob) {
|
||||
a.cronjob = d
|
||||
a.workload = d
|
||||
if v, ok := d.Spec.JobTemplate.Labels["version"]; ok && v != "" {
|
||||
a.DeployVersion = v
|
||||
}
|
||||
a.calculateComponentMemoryRequest()
|
||||
}
|
||||
|
||||
//SetReplicaSets set kubernetes replicaset
|
||||
func (a *AppService) SetReplicaSets(d *v1.ReplicaSet) {
|
||||
if len(a.replicasets) > 0 {
|
||||
@ -522,6 +573,12 @@ func (a *AppService) SetPodTemplate(d corev1.PodTemplateSpec) {
|
||||
if a.deployment != nil {
|
||||
a.deployment.Spec.Template = d
|
||||
}
|
||||
if a.job != nil {
|
||||
a.job.Spec.Template = d
|
||||
}
|
||||
if a.cronjob != nil {
|
||||
a.cronjob.Spec.JobTemplate.Spec.Template = d
|
||||
}
|
||||
a.calculateComponentMemoryRequest()
|
||||
}
|
||||
|
||||
@ -533,6 +590,12 @@ func (a *AppService) GetPodTemplate() *corev1.PodTemplateSpec {
|
||||
if a.deployment != nil {
|
||||
return &a.deployment.Spec.Template
|
||||
}
|
||||
if a.job != nil {
|
||||
return &a.job.Spec.Template
|
||||
}
|
||||
if a.cronjob != nil {
|
||||
return &a.cronjob.Spec.JobTemplate.Spec.Template
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,12 @@ func (g *GarbageCollector) DelKubernetesObjects(serviceGCReq model.ServiceGCTask
|
||||
if err := g.clientset.AppsV1().StatefulSets(namespace).DeleteCollection(context.Background(), deleteOpts, listOpts); err != nil {
|
||||
logrus.Warningf("[DelKubernetesObjects] delete statefulsets(%s): %v", serviceGCReq.ServiceID, err)
|
||||
}
|
||||
if err := g.clientset.BatchV1().Jobs(namespace).DeleteCollection(context.Background(), deleteOpts, listOpts); err != nil {
|
||||
logrus.Warningf("[DelKubernetesObjects] delete job(%s): %v", serviceGCReq.ServiceID, err)
|
||||
}
|
||||
if err := g.clientset.BatchV1beta1().CronJobs(namespace).DeleteCollection(context.Background(), deleteOpts, listOpts); err != nil {
|
||||
logrus.Warningf("[DelKubernetesObjects] delete cronjob(%s): %v", serviceGCReq.ServiceID, err)
|
||||
}
|
||||
if err := g.clientset.ExtensionsV1beta1().Ingresses(namespace).DeleteCollection(context.Background(), deleteOpts, listOpts); err != nil {
|
||||
logrus.Warningf("[DelKubernetesObjects] delete extensions ingresses(%s): %v", serviceGCReq.ServiceID, err)
|
||||
}
|
||||
@ -151,6 +157,7 @@ func (g *GarbageCollector) DelKubernetesObjects(serviceGCReq model.ServiceGCTask
|
||||
}
|
||||
}
|
||||
|
||||
// listOptionsServiceID -
|
||||
func (g *GarbageCollector) listOptionsServiceID(serviceID string) metav1.ListOptions {
|
||||
labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{
|
||||
"creator": "Rainbond",
|
||||
@ -160,3 +167,13 @@ func (g *GarbageCollector) listOptionsServiceID(serviceID string) metav1.ListOpt
|
||||
LabelSelector: labels.Set(labelSelector.MatchLabels).String(),
|
||||
}
|
||||
}
|
||||
|
||||
// DelComponentPkg deletes component package
|
||||
func (g *GarbageCollector) DelComponentPkg(serviceGCReq model.ServiceGCTaskBody) {
|
||||
logrus.Infof("service id: %s; delete component package.", serviceGCReq.ServiceID)
|
||||
// log generated during service running
|
||||
pkgPath := fmt.Sprintf("/grdata/package_build/components/%s", serviceGCReq.ServiceID)
|
||||
if err := os.RemoveAll(pkgPath); err != nil {
|
||||
logrus.Warningf("remove component package: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -463,6 +463,7 @@ func (m *Manager) ExecServiceGCTask(task *model.Task) error {
|
||||
m.garbageCollector.DelPvPvcByServiceID(serviceGCReq)
|
||||
m.garbageCollector.DelVolumeData(serviceGCReq)
|
||||
m.garbageCollector.DelKubernetesObjects(serviceGCReq)
|
||||
m.garbageCollector.DelComponentPkg(serviceGCReq)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -701,10 +701,10 @@ func (r *RuntimeServer) GetAppVolumeStatus(ctx context.Context, re *pb.ServiceRe
|
||||
pods := as.GetPods(false)
|
||||
for _, pod := range pods {
|
||||
// if pod is terminated, volume status of pod is NOT_READY
|
||||
if v1.IsPodTerminated(pod) {
|
||||
continue
|
||||
}
|
||||
// Exception pod information due to node loss is no longer displayed, so volume status is NOT_READY
|
||||
// if v1.IsPodTerminated(pod) {
|
||||
// continue
|
||||
// }
|
||||
// // Exception pod information due to node loss is no longer displayed, so volume status is NOT_READY
|
||||
if v1.IsPodNodeLost(pod) {
|
||||
continue
|
||||
}
|
||||
|
@ -94,6 +94,19 @@ func DescribePodStatus(clientset kubernetes.Interface, pod *corev1.Pod, podStatu
|
||||
if cstatus.State.Terminated.Reason == "OOMKilled" {
|
||||
podStatus.Advice = PodStatusAdviceOOM.String()
|
||||
}
|
||||
for _, OwnerReference := range pod.OwnerReferences{
|
||||
if OwnerReference.Kind == "Job"{
|
||||
if cstatus.State.Terminated.Reason == "Completed" {
|
||||
podStatus.Type = pb.PodStatus_SUCCEEDED
|
||||
}
|
||||
if cstatus.State.Terminated.Reason == "DeadlineExceeded" {
|
||||
podStatus.Type = pb.PodStatus_FAILED
|
||||
}
|
||||
if cstatus.State.Terminated.Reason == "Error" {
|
||||
podStatus.Type = pb.PodStatus_ABNORMAL
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if !cstatus.Ready {
|
||||
|
Loading…
Reference in New Issue
Block a user