Rainbond/api/handler/resource.go

250 lines
8.5 KiB
Go

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
}