mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-12-02 03:37:46 +08:00
ef74adb800
* perf: modify variable name * feat: add K8s Attribute VolumeClaimTemplate
460 lines
18 KiB
Go
460 lines
18 KiB
Go
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/sirupsen/logrus"
|
|
"io/ioutil"
|
|
appv1 "k8s.io/api/apps/v1"
|
|
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
|
batchv1 "k8s.io/api/batch/v1"
|
|
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, api_model.YamlSourceFile, "")
|
|
var DeployNames, JobNames, CJNames, STSNames, 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:
|
|
STSNames = append(STSNames, 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: STSNames,
|
|
},
|
|
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")
|
|
source := api_model.YamlSourceFile
|
|
if yamlResource.Yaml != "" {
|
|
source = api_model.YamlSourceHelm
|
|
}
|
|
k8sResourceObjects := c.YamlToResource(yamlResource, source, yamlResource.Yaml)
|
|
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 := api_model.CreateSuccess
|
|
switch buildResource.Resource.GetKind() {
|
|
case api_model.Deployment:
|
|
deployJSON, _ := json.Marshal(buildResource.Resource)
|
|
var deployObject appv1.Deployment
|
|
json.Unmarshal(deployJSON, &deployObject)
|
|
memory, cpu := deployObject.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().Value(), deployObject.Spec.Template.Spec.Containers[0].Resources.Requests.Cpu().MilliValue()
|
|
if memory == 0 {
|
|
memory = deployObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value()
|
|
}
|
|
if cpu == 0 {
|
|
cpu = deployObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().MilliValue()
|
|
}
|
|
basic := api_model.BasicManagement{
|
|
ResourceType: api_model.Deployment,
|
|
Replicas: deployObject.Spec.Replicas,
|
|
Memory: memory / 1024 / 1024,
|
|
CPU: cpu,
|
|
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, nil)
|
|
case api_model.Job:
|
|
jobJSON, _ := json.Marshal(buildResource.Resource)
|
|
var jobObject batchv1.Job
|
|
json.Unmarshal(jobJSON, &jobObject)
|
|
memory, cpu := jobObject.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().Value(), jobObject.Spec.Template.Spec.Containers[0].Resources.Requests.Cpu().MilliValue()
|
|
if memory == 0 {
|
|
memory = jobObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value()
|
|
}
|
|
if cpu == 0 {
|
|
cpu = jobObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().MilliValue()
|
|
}
|
|
basic := api_model.BasicManagement{
|
|
ResourceType: api_model.Job,
|
|
Replicas: jobObject.Spec.Completions,
|
|
Memory: memory / 1024 / 1024,
|
|
CPU: cpu,
|
|
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, nil)
|
|
case api_model.CronJob:
|
|
cjJSON, _ := json.Marshal(buildResource.Resource)
|
|
var cjObject batchv1.CronJob
|
|
json.Unmarshal(cjJSON, &cjObject)
|
|
memory, cpu := cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().Value(), cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Requests.Cpu().MilliValue()
|
|
if memory == 0 {
|
|
memory = cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value()
|
|
}
|
|
if cpu == 0 {
|
|
cpu = cjObject.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().MilliValue()
|
|
}
|
|
basic := api_model.BasicManagement{
|
|
ResourceType: api_model.CronJob,
|
|
Replicas: cjObject.Spec.JobTemplate.Spec.Completions,
|
|
Memory: memory / 1024 / 1024,
|
|
CPU: cpu,
|
|
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, nil)
|
|
case api_model.StateFulSet:
|
|
stsJSON, _ := json.Marshal(buildResource.Resource)
|
|
var stsObject appv1.StatefulSet
|
|
json.Unmarshal(stsJSON, &stsObject)
|
|
memory, cpu := stsObject.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().Value(), stsObject.Spec.Template.Spec.Containers[0].Resources.Requests.Cpu().MilliValue()
|
|
if memory == 0 {
|
|
memory = stsObject.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().Value()
|
|
}
|
|
if cpu == 0 {
|
|
cpu = stsObject.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().MilliValue()
|
|
}
|
|
basic := api_model.BasicManagement{
|
|
ResourceType: api_model.StateFulSet,
|
|
Replicas: stsObject.Spec.Replicas,
|
|
Memory: memory / 1024 / 1024,
|
|
CPU: cpu,
|
|
Image: stsObject.Spec.Template.Spec.Containers[0].Image,
|
|
Cmd: strings.Join(append(stsObject.Spec.Template.Spec.Containers[0].Command, stsObject.Spec.Template.Spec.Containers[0].Args...), " "),
|
|
}
|
|
parameter := api_model.YamlResourceParameter{
|
|
ComponentsCR: &ConvertResource,
|
|
Basic: basic,
|
|
Template: stsObject.Spec.Template,
|
|
Namespace: yamlResource.Namespace,
|
|
Name: buildResource.Resource.GetName(),
|
|
RsLabel: stsObject.Labels,
|
|
HPAs: hpas,
|
|
CMs: cms,
|
|
}
|
|
c.PodTemplateSpecResource(parameter, stsObject.Spec.VolumeClaimTemplates)
|
|
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)
|
|
continue
|
|
}
|
|
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
|
|
k8sResource, err := c.CreateK8sResource(components.KubernetesResources, app.AppID)
|
|
if err != nil {
|
|
logrus.Errorf("create K8sResources err:%v", err)
|
|
return ar, &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 ar, &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,
|
|
}
|
|
|
|
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, yamlSource, yamlContent string) []api_model.K8sResourceObject {
|
|
yamlDirectoryPath := path.Join("/grdata/package_build/temp/events", yamlResource.EventID, "*")
|
|
yamlFilesPath := []string{api_model.YamlSourceHelm}
|
|
if yamlSource == api_model.YamlSourceFile {
|
|
yamlFilesPath, _ = filepath.Glob(yamlDirectoryPath)
|
|
}
|
|
var fileBuildResourceList []api_model.K8sResourceObject
|
|
for _, yamlFilePath := range yamlFilesPath {
|
|
var fileName string
|
|
yamlFileBytes := []byte(yamlContent)
|
|
if yamlSource == api_model.YamlSourceFile {
|
|
fileName = path.Base(yamlFilePath)
|
|
var err error
|
|
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) {
|
|
logrus.Infof("begin ResourceCreate function")
|
|
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
|
|
}
|