Rainbond/api/handler/application_handler.go

773 lines
25 KiB
Go
Raw Normal View History

2020-09-17 15:45:46 +08:00
package handler
import (
2020-09-28 16:43:27 +08:00
"context"
2020-09-27 16:27:46 +08:00
"fmt"
2021-11-11 09:55:17 +08:00
governance_mode "github.com/goodrain/rainbond/api/handler/app_governance_mode"
2021-04-23 10:03:15 +08:00
"sort"
2020-09-28 16:43:27 +08:00
"strconv"
"time"
"github.com/goodrain/rainbond/api/client/prometheus"
2020-09-17 15:45:46 +08:00
"github.com/goodrain/rainbond/api/model"
2020-09-20 01:09:29 +08:00
"github.com/goodrain/rainbond/api/util/bcode"
2020-09-17 15:45:46 +08:00
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
2021-04-16 10:07:34 +08:00
"github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
2021-04-17 15:47:59 +08:00
util "github.com/goodrain/rainbond/util"
2021-04-16 10:07:34 +08:00
"github.com/goodrain/rainbond/util/commonutil"
2021-05-12 11:13:36 +08:00
"github.com/goodrain/rainbond/util/constants"
2020-09-28 16:43:27 +08:00
"github.com/goodrain/rainbond/worker/client"
"github.com/goodrain/rainbond/worker/server/pb"
2021-04-14 20:17:40 +08:00
"github.com/jinzhu/gorm"
2021-04-16 16:27:21 +08:00
"github.com/pkg/errors"
2020-09-27 16:27:46 +08:00
"github.com/sirupsen/logrus"
2021-05-12 11:13:36 +08:00
corev1 "k8s.io/api/core/v1"
2021-04-16 16:27:21 +08:00
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
2021-04-16 10:07:34 +08:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021-04-17 15:47:59 +08:00
clientset "k8s.io/client-go/kubernetes"
2020-09-17 15:45:46 +08:00
)
// ApplicationAction -
2020-09-28 16:43:27 +08:00
type ApplicationAction struct {
2021-04-16 10:07:34 +08:00
statusCli *client.AppRuntimeSyncClient
promClient prometheus.Interface
rainbondClient versioned.Interface
2021-04-17 15:47:59 +08:00
kubeClient clientset.Interface
2020-09-28 16:43:27 +08:00
}
2020-09-17 15:45:46 +08:00
// ApplicationHandler defines handler methods to TenantApplication.
type ApplicationHandler interface {
2021-04-16 10:07:34 +08:00
CreateApp(ctx context.Context, req *model.Application) (*model.Application, error)
BatchCreateApp(ctx context.Context, req *model.CreateAppRequest, tenantID string) ([]model.CreateAppResponse, error)
2021-04-26 14:51:23 +08:00
UpdateApp(ctx context.Context, app *dbmodel.Application, req model.UpdateAppRequest) (*dbmodel.Application, error)
2020-09-20 02:07:10 +08:00
ListApps(tenantID, appName string, page, pageSize int) (*model.ListAppResponse, error)
2020-09-18 11:26:01 +08:00
GetAppByID(appID string) (*dbmodel.Application, error)
BatchBindService(appID string, req model.BindServiceRequest) error
2021-04-21 18:17:15 +08:00
DeleteApp(ctx context.Context, app *dbmodel.Application) error
2020-09-28 16:43:27 +08:00
2020-09-22 15:51:57 +08:00
AddConfigGroup(appID string, req *model.ApplicationConfigGroup) (*model.ApplicationConfigGroupResp, error)
2020-09-24 14:30:34 +08:00
UpdateConfigGroup(appID, configGroupName string, req *model.UpdateAppConfigGroupReq) (*model.ApplicationConfigGroupResp, error)
2020-09-28 16:43:27 +08:00
2020-09-30 11:03:14 +08:00
BatchUpdateComponentPorts(appID string, ports []*model.AppPort) error
2021-04-19 17:34:56 +08:00
GetStatus(ctx context.Context, app *dbmodel.Application) (*model.AppStatus, error)
2021-04-29 15:56:34 +08:00
Install(ctx context.Context, app *dbmodel.Application, overrides []string) error
2021-04-17 15:47:59 +08:00
ListServices(ctx context.Context, app *dbmodel.Application) ([]*model.AppService, error)
2021-04-27 11:13:54 +08:00
ListHelmAppReleases(ctx context.Context, app *dbmodel.Application) ([]*model.HelmAppRelease, error)
2020-09-24 14:30:34 +08:00
DeleteConfigGroup(appID, configGroupName string) error
ListConfigGroups(appID string, page, pageSize int) (*model.ListApplicationConfigGroupResp, error)
2021-06-19 19:41:28 +08:00
SyncComponents(app *dbmodel.Application, components []*model.Component, deleteComponentIDs []string) error
SyncComponentConfigGroupRels(tx *gorm.DB, app *dbmodel.Application, components []*model.Component) error
2021-06-09 15:04:20 +08:00
SyncAppConfigGroups(app *dbmodel.Application, appConfigGroups []model.AppConfigGroup) error
2021-07-22 16:01:08 +08:00
ListAppStatuses(ctx context.Context, appIDs []string) ([]*model.AppStatus, error)
2021-11-11 09:55:17 +08:00
CheckGovernanceMode(ctx context.Context, governanceMode string) error
2020-09-17 15:45:46 +08:00
}
// NewApplicationHandler creates a new Tenant Application Handler.
2021-04-17 15:47:59 +08:00
func NewApplicationHandler(statusCli *client.AppRuntimeSyncClient, promClient prometheus.Interface, rainbondClient versioned.Interface, kubeClient clientset.Interface) ApplicationHandler {
2020-09-28 16:43:27 +08:00
return &ApplicationAction{
2021-04-16 16:27:21 +08:00
statusCli: statusCli,
promClient: promClient,
rainbondClient: rainbondClient,
2021-04-17 15:47:59 +08:00
kubeClient: kubeClient,
2020-09-28 16:43:27 +08:00
}
2020-09-17 15:45:46 +08:00
}
// CreateApp -
2021-04-16 10:07:34 +08:00
func (a *ApplicationAction) CreateApp(ctx context.Context, req *model.Application) (*model.Application, error) {
appID := util.NewUUID()
if req.K8sApp == "" {
req.K8sApp = fmt.Sprintf("app-%s", appID[:8])
}
2020-09-17 15:45:46 +08:00
appReq := &dbmodel.Application{
2021-04-16 10:07:34 +08:00
EID: req.EID,
TenantID: req.TenantID,
AppID: appID,
2021-04-16 10:07:34 +08:00
AppName: req.AppName,
AppType: req.AppType,
AppStoreName: req.AppStoreName,
2021-04-16 17:48:26 +08:00
AppStoreURL: req.AppStoreURL,
2021-04-16 10:07:34 +08:00
AppTemplateName: req.AppTemplateName,
Version: req.Version,
K8sApp: req.K8sApp,
2020-09-17 15:45:46 +08:00
}
2020-09-18 14:05:48 +08:00
req.AppID = appReq.AppID
2021-04-16 16:27:21 +08:00
err := db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
if db.GetManager().ApplicationDaoTransactions(tx).IsK8sAppDuplicate(appReq.TenantID, appID, appReq.K8sApp) {
return bcode.ErrK8sAppExists
}
2021-04-14 20:17:40 +08:00
if err := db.GetManager().ApplicationDaoTransactions(tx).AddModel(appReq); err != nil {
return err
}
2021-04-14 20:17:40 +08:00
if len(req.ServiceIDs) != 0 {
if err := db.GetManager().TenantServiceDaoTransactions(tx).BindAppByServiceIDs(appReq.AppID, req.ServiceIDs); err != nil {
return err
}
}
2021-04-23 10:03:15 +08:00
if appReq.AppType == model.AppTypeHelm {
// create helmapp.rainbond.io
2021-04-23 10:03:15 +08:00
return a.createHelmApp(ctx, appReq)
}
return nil
2021-04-14 20:17:40 +08:00
})
return req, err
2020-09-17 15:45:46 +08:00
}
2020-09-17 16:43:53 +08:00
2021-04-16 10:07:34 +08:00
func (a *ApplicationAction) createHelmApp(ctx context.Context, app *dbmodel.Application) error {
2021-05-12 11:13:36 +08:00
labels := map[string]string{
constants.ResourceManagedByLabel: constants.Rainbond,
}
tenant, err := GetTenantManager().GetTenantsByUUID(app.TenantID)
if err != nil {
return errors.Wrap(err, "get tenant for helm app failed")
}
2021-04-16 10:07:34 +08:00
helmApp := &v1alpha1.HelmApp{
ObjectMeta: metav1.ObjectMeta{
Name: app.AppName,
Namespace: tenant.Namespace,
2021-05-12 11:13:36 +08:00
Labels: labels,
2021-04-16 10:07:34 +08:00
},
Spec: v1alpha1.HelmAppSpec{
EID: app.EID,
TemplateName: app.AppTemplateName,
Version: app.Version,
AppStore: &v1alpha1.HelmAppStore{
2021-05-12 11:13:36 +08:00
Name: app.AppStoreName,
URL: app.AppStoreURL,
2021-04-16 10:07:34 +08:00
},
}}
2021-05-12 11:13:36 +08:00
ctx1, cancel := context.WithTimeout(ctx, 3*time.Second)
2021-04-16 16:27:21 +08:00
defer cancel()
_, err = a.kubeClient.CoreV1().Namespaces().Create(ctx1, &corev1.Namespace{
2021-05-12 11:13:36 +08:00
ObjectMeta: metav1.ObjectMeta{
Name: tenant.Namespace,
2021-05-12 11:13:36 +08:00
Labels: labels,
},
}, metav1.CreateOptions{})
if err != nil && !k8sErrors.IsAlreadyExists(err) {
return errors.Wrap(err, "create namespace for helm app")
}
ctx2, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
_, err = a.rainbondClient.RainbondV1alpha1().HelmApps(helmApp.Namespace).Create(ctx2, helmApp, metav1.CreateOptions{})
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
return errors.Wrap(bcode.ErrApplicationExist, "create helm app")
}
return errors.Wrap(err, "create helm app")
2021-04-16 17:48:26 +08:00
}
2021-05-12 11:13:36 +08:00
return nil
2021-04-16 10:07:34 +08:00
}
2020-11-10 16:12:40 +08:00
// BatchCreateApp -
2021-04-16 10:07:34 +08:00
func (a *ApplicationAction) BatchCreateApp(ctx context.Context, apps *model.CreateAppRequest, tenantID string) ([]model.CreateAppResponse, error) {
2020-11-10 16:12:40 +08:00
var (
resp model.CreateAppResponse
respList []model.CreateAppResponse
)
for _, app := range apps.AppsInfo {
app.TenantID = tenantID
2021-04-16 10:07:34 +08:00
regionApp, err := GetApplicationHandler().CreateApp(ctx, &app)
2020-11-10 16:12:40 +08:00
if err != nil {
logrus.Errorf("Batch Create App [%v] error is [%v] ", app.AppName, err)
2020-11-10 16:47:44 +08:00
continue
2020-11-10 16:12:40 +08:00
}
resp.AppID = app.ConsoleAppID
resp.RegionAppID = regionApp.AppID
respList = append(respList, resp)
}
return respList, nil
}
2020-09-18 11:39:05 +08:00
// UpdateApp -
2021-04-26 14:51:23 +08:00
func (a *ApplicationAction) UpdateApp(ctx context.Context, app *dbmodel.Application, req model.UpdateAppRequest) (*dbmodel.Application, error) {
2020-11-07 10:11:33 +08:00
if req.AppName != "" {
2021-04-26 14:51:23 +08:00
app.AppName = req.AppName
2020-11-07 10:11:33 +08:00
}
if req.GovernanceMode != "" {
2021-11-11 09:55:17 +08:00
if !governance_mode.IsGovernanceModeValid(req.GovernanceMode) {
logrus.Errorf("governance mode '%s' is invalid", req.GovernanceMode)
return nil, bcode.ErrInvalidGovernanceMode
2020-11-07 10:11:33 +08:00
}
2021-04-26 14:51:23 +08:00
app.GovernanceMode = req.GovernanceMode
2020-11-07 10:11:33 +08:00
}
app.K8sApp = req.K8sApp
2021-04-26 14:51:23 +08:00
err := db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
if db.GetManager().ApplicationDaoTransactions(tx).IsK8sAppDuplicate(app.TenantID, app.AppID, req.K8sApp) {
return bcode.ErrK8sAppExists
}
if err := db.GetManager().ApplicationDaoTransactions(tx).UpdateModel(app); err != nil {
2021-04-26 14:51:23 +08:00
return err
}
2021-04-27 11:13:54 +08:00
if req.NeedUpdateHelmApp() {
if err := a.updateHelmApp(ctx, app, req); err != nil {
return err
2021-04-26 14:51:23 +08:00
}
}
return nil
})
return app, err
2020-09-18 11:39:05 +08:00
}
2021-04-27 11:13:54 +08:00
func (a *ApplicationAction) updateHelmApp(ctx context.Context, app *dbmodel.Application, req model.UpdateAppRequest) error {
tenant, err := GetTenantManager().GetTenantsByUUID(app.TenantID)
if err != nil {
return errors.Wrap(err, "get tenant for helm app failed")
}
2021-04-27 11:13:54 +08:00
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
helmApp, err := a.rainbondClient.RainbondV1alpha1().HelmApps(tenant.Namespace).Get(ctx, app.AppName, metav1.GetOptions{})
2021-04-27 11:13:54 +08:00
if err != nil {
if k8sErrors.IsNotFound(err) {
return errors.Wrap(bcode.ErrApplicationNotFound, "update app")
}
return errors.Wrap(err, "update app")
}
helmApp.Spec.Overrides = req.Overrides
2021-04-27 11:13:54 +08:00
if req.Version != "" {
helmApp.Spec.Version = req.Version
}
if req.Revision != 0 {
helmApp.Spec.Revision = req.Revision
}
_, err = a.rainbondClient.RainbondV1alpha1().HelmApps(tenant.Namespace).Update(ctx, helmApp, metav1.UpdateOptions{})
2021-04-27 11:13:54 +08:00
return err
}
2020-09-17 16:43:53 +08:00
// ListApps -
func (a *ApplicationAction) ListApps(tenantID, appName string, page, pageSize int) (*model.ListAppResponse, error) {
2020-09-19 21:17:40 +08:00
var resp model.ListAppResponse
2020-09-23 15:30:31 +08:00
apps, total, err := db.GetManager().ApplicationDao().ListApps(tenantID, appName, page, pageSize)
2020-09-19 21:17:40 +08:00
if err != nil {
return nil, err
2020-09-17 16:43:53 +08:00
}
2020-09-19 21:17:40 +08:00
if apps != nil {
resp.Apps = apps
} else {
resp.Apps = make([]*dbmodel.Application, 0)
}
resp.Page = page
resp.Total = total
resp.PageSize = pageSize
return &resp, nil
2020-09-17 16:43:53 +08:00
}
2020-09-18 11:26:01 +08:00
// GetAppByID -
func (a *ApplicationAction) GetAppByID(appID string) (*dbmodel.Application, error) {
2020-09-23 15:30:31 +08:00
app, err := db.GetManager().ApplicationDao().GetAppByID(appID)
2020-09-18 11:26:01 +08:00
if err != nil {
return nil, err
}
return app, nil
}
2020-09-18 18:08:32 +08:00
// DeleteApp -
2021-04-21 18:17:15 +08:00
func (a *ApplicationAction) DeleteApp(ctx context.Context, app *dbmodel.Application) error {
2021-04-27 17:46:25 +08:00
if app.AppType == dbmodel.AppTypeHelm {
return a.deleteHelmApp(ctx, app)
}
return a.deleteRainbondApp(app)
}
func (a *ApplicationAction) deleteRainbondApp(app *dbmodel.Application) error {
// can't delete rainbond app with components
if err := a.isContainComponents(app.AppID); err != nil {
return err
}
return db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
return errors.WithMessage(a.deleteApp(tx, app), "delete app from db")
})
}
// isContainComponents checks if the app contains components.
func (a *ApplicationAction) isContainComponents(appID string) error {
total, err := db.GetManager().TenantServiceDao().CountServiceByAppID(appID)
if err != nil {
return err
}
if total != 0 {
2020-09-20 01:09:29 +08:00
return bcode.ErrDeleteDueToBindService
}
2021-04-27 17:46:25 +08:00
return nil
}
2021-04-21 18:17:15 +08:00
2021-04-27 17:46:25 +08:00
func (a *ApplicationAction) deleteHelmApp(ctx context.Context, app *dbmodel.Application) error {
2021-04-21 19:45:00 +08:00
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
2021-04-21 18:17:15 +08:00
defer cancel()
tenant, err := GetTenantManager().GetTenantsByUUID(app.TenantID)
if err != nil {
return errors.Wrap(err, "get tenant for helm app failed")
}
2021-04-21 18:17:15 +08:00
return db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
2021-04-27 17:46:25 +08:00
if err := a.deleteApp(tx, app); err != nil {
2021-04-21 18:17:15 +08:00
return err
}
if err := a.rainbondClient.RainbondV1alpha1().HelmApps(tenant.Namespace).Delete(ctx, app.AppName, metav1.DeleteOptions{}); err != nil {
2021-04-21 18:17:15 +08:00
if !k8sErrors.IsNotFound(err) {
return err
}
}
return nil
})
2020-09-18 18:08:32 +08:00
}
2020-10-08 14:01:37 +08:00
2021-04-27 17:46:25 +08:00
func (a *ApplicationAction) deleteApp(tx *gorm.DB, app *dbmodel.Application) error {
// delete app config group service
if err := db.GetManager().AppConfigGroupServiceDaoTransactions(tx).DeleteByAppID(app.AppID); err != nil {
return err
}
// delete config group items
if err := db.GetManager().AppConfigGroupItemDaoTransactions(tx).DeleteByAppID(app.AppID); err != nil {
return err
}
// delete config group
if err := db.GetManager().AppConfigGroupDaoTransactions(tx).DeleteByAppID(app.AppID); err != nil {
return err
}
// delete application
return db.GetManager().ApplicationDaoTransactions(tx).DeleteApp(app.AppID)
}
2020-09-30 11:03:14 +08:00
// BatchUpdateComponentPorts -
func (a *ApplicationAction) BatchUpdateComponentPorts(appID string, ports []*model.AppPort) error {
2020-09-27 16:27:46 +08:00
if err := a.checkPorts(appID, ports); err != nil {
return err
}
tx := db.GetManager().Begin()
defer func() {
if r := recover(); r != nil {
logrus.Errorf("Unexpected panic occurred, rollback transaction: %v", r)
tx.Rollback()
}
}()
// update port
for _, p := range ports {
port, err := db.GetManager().TenantServicesPortDaoTransactions(tx).GetPort(p.ServiceID, p.ContainerPort)
if err != nil {
tx.Rollback()
return err
}
port.PortAlias = p.PortAlias
port.K8sServiceName = p.K8sServiceName
err = db.GetManager().TenantServicesPortDaoTransactions(tx).UpdateModel(port)
if err != nil {
tx.Rollback()
return err
}
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return err
}
return nil
}
func (a *ApplicationAction) checkPorts(appID string, ports []*model.AppPort) error {
// check if the ports are belong to the given appID
services, err := db.GetManager().TenantServiceDao().ListByAppID(appID)
if err != nil {
return err
}
set := make(map[string]struct{})
for _, svc := range services {
set[svc.ServiceID] = struct{}{}
}
var k8sServiceNames []string
key2ports := make(map[string]*model.AppPort)
for i := range ports {
port := ports[i]
if _, ok := set[port.ServiceID]; !ok {
return bcode.NewBadRequest(fmt.Sprintf("port(%s) is not belong to app(%s)", port.ServiceID, appID))
}
k8sServiceNames = append(k8sServiceNames, port.ServiceID)
key2ports[port.ServiceID+strconv.Itoa(port.ContainerPort)] = port
}
// check if k8s_service_name is unique
servicesPorts, err := db.GetManager().TenantServicesPortDao().ListByK8sServiceNames(k8sServiceNames)
if err != nil {
return err
}
for _, port := range servicesPorts {
// check if the port is as same as the one in request
if _, ok := key2ports[port.ServiceID+strconv.Itoa(port.ContainerPort)]; !ok {
logrus.Errorf("kubernetes service name(%s) already exists", port.K8sServiceName)
return bcode.ErrK8sServiceNameExists
}
}
return nil
}
2020-09-28 16:43:27 +08:00
2020-09-30 11:03:14 +08:00
// GetStatus -
2021-04-19 17:34:56 +08:00
func (a *ApplicationAction) GetStatus(ctx context.Context, app *dbmodel.Application) (*model.AppStatus, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
2020-09-28 16:43:27 +08:00
defer cancel()
status, err := a.statusCli.GetAppStatus(ctx, &pb.AppStatusReq{
2021-04-16 17:48:26 +08:00
AppId: app.AppID,
2020-09-28 16:43:27 +08:00
})
if err != nil {
2021-04-19 17:34:56 +08:00
return nil, errors.Wrap(err, "get app status")
2020-09-28 16:43:27 +08:00
}
2021-05-11 10:32:55 +08:00
var conditions []*model.AppStatusCondition
for _, cdt := range status.Conditions {
conditions = append(conditions, &model.AppStatusCondition{
2021-07-01 13:35:25 +08:00
Type: cdt.Type,
2021-05-11 10:32:55 +08:00
Status: cdt.Status,
Reason: cdt.Reason,
Message: cdt.Message,
})
}
2021-04-16 17:48:26 +08:00
diskUsage := a.getDiskUsage(app.AppID)
2020-09-28 16:43:27 +08:00
2021-04-26 14:51:23 +08:00
var cpu *int64
if status.SetCPU {
cpu = commonutil.Int64(status.Cpu)
}
var memory *int64
if status.SetMemory {
memory = commonutil.Int64(status.Memory)
}
2020-09-28 16:43:27 +08:00
res := &model.AppStatus{
2021-05-11 10:32:55 +08:00
Status: status.Status,
2021-05-12 11:39:38 +08:00
CPU: cpu,
2021-05-11 10:32:55 +08:00
Memory: memory,
Disk: int64(diskUsage),
Phase: status.Phase,
Overrides: status.Overrides,
Version: status.Version,
Conditions: conditions,
2021-07-22 16:01:08 +08:00
AppID: app.AppID,
AppName: app.AppName,
2020-09-28 16:43:27 +08:00
}
return res, nil
}
2021-05-12 11:39:38 +08:00
// Install installs the application.
2021-04-29 15:56:34 +08:00
func (a *ApplicationAction) Install(ctx context.Context, app *dbmodel.Application, overrides []string) error {
2021-04-20 22:27:09 +08:00
ctx1, cancel := context.WithTimeout(ctx, 3*time.Second)
2021-04-16 21:22:16 +08:00
defer cancel()
tenant, err := db.GetManager().TenantDao().GetTenantByUUID(app.TenantID)
if err != nil {
return errors.Wrap(err, "install app")
}
helmApp, err := a.rainbondClient.RainbondV1alpha1().HelmApps(tenant.Namespace).Get(ctx1, app.AppName, metav1.GetOptions{})
2021-04-16 21:22:16 +08:00
if err != nil {
if k8sErrors.IsNotFound(err) {
2021-04-21 16:14:59 +08:00
return errors.Wrap(bcode.ErrApplicationNotFound, "install app")
2021-04-16 21:22:16 +08:00
}
2021-04-21 16:14:59 +08:00
return errors.Wrap(err, "install app")
2021-04-16 21:22:16 +08:00
}
2021-04-20 22:27:09 +08:00
ctx3, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
2021-04-29 15:56:34 +08:00
helmApp.Spec.Overrides = overrides
2021-05-06 09:34:15 +08:00
helmApp.Spec.PreStatus = v1alpha1.HelmAppPreStatusConfigured
_, err = a.rainbondClient.RainbondV1alpha1().HelmApps(tenant.Namespace).Update(ctx3, helmApp, metav1.UpdateOptions{})
2021-04-20 22:27:09 +08:00
if err != nil {
2021-04-21 16:14:59 +08:00
return err
2021-04-20 22:27:09 +08:00
}
2021-04-21 16:14:59 +08:00
return errors.Wrap(err, "install app")
2021-04-16 21:22:16 +08:00
}
2021-05-12 11:39:38 +08:00
// ListServices returns the list of the application.
2021-04-17 15:47:59 +08:00
func (a *ApplicationAction) ListServices(ctx context.Context, app *dbmodel.Application) ([]*model.AppService, error) {
nctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
2021-04-20 11:25:24 +08:00
appServices, err := a.statusCli.ListAppServices(nctx, &pb.AppReq{AppId: app.AppID})
2021-04-17 15:47:59 +08:00
if err != nil {
return nil, err
}
var services []*model.AppService
2021-04-20 11:25:24 +08:00
for _, service := range appServices.Services {
2021-04-17 15:47:59 +08:00
svc := &model.AppService{
ServiceName: service.Name,
2021-04-21 15:12:34 +08:00
Address: service.Address,
2021-04-17 15:47:59 +08:00
}
2021-05-11 10:32:55 +08:00
svc.Pods = a.convertPods(service.Pods)
svc.OldPods = a.convertPods(service.OldPods)
svc.Ports = append(svc.Ports, service.Ports...)
2021-04-17 15:47:59 +08:00
services = append(services, svc)
}
2021-04-23 10:03:15 +08:00
sort.Sort(model.ByServiceName(services))
2021-04-17 15:47:59 +08:00
return services, nil
}
2021-05-11 10:32:55 +08:00
func (a *ApplicationAction) convertPods(pods []*pb.AppService_Pod) []*model.AppPod {
var res []*model.AppPod
for _, pod := range pods {
res = append(res, &model.AppPod{
PodName: pod.Name,
PodStatus: pod.Status,
})
}
sort.Sort(model.ByPodName(res))
return res
}
2020-09-28 16:43:27 +08:00
func (a *ApplicationAction) getDiskUsage(appID string) float64 {
var result float64
2020-09-30 11:03:14 +08:00
query := fmt.Sprintf(`sum(max(app_resource_appfs{app_id=~"%s"}) by(app_id))`, appID)
2020-09-28 16:43:27 +08:00
metric := a.promClient.GetMetric(query, time.Now())
for _, m := range metric.MetricData.MetricValues {
result += m.Sample.Value()
}
return result
}
2020-11-07 10:11:33 +08:00
// BatchBindService -
func (a *ApplicationAction) BatchBindService(appID string, req model.BindServiceRequest) error {
var serviceIDs []string
2020-11-09 15:48:35 +08:00
for _, sid := range req.ServiceIDs {
2020-10-23 14:17:30 +08:00
if _, err := db.GetManager().TenantServiceDao().GetServiceByID(sid); err != nil {
if err == gorm.ErrRecordNotFound {
continue
}
2020-10-23 14:17:30 +08:00
return err
}
serviceIDs = append(serviceIDs, sid)
2020-10-23 14:17:30 +08:00
}
return db.GetManager().TenantServiceDao().BindAppByServiceIDs(appID, serviceIDs)
2020-10-09 09:15:21 +08:00
}
2021-04-21 19:45:00 +08:00
2021-05-12 11:39:38 +08:00
// ListHelmAppReleases returns the list of the helm app.
2021-04-27 11:13:54 +08:00
func (a *ApplicationAction) ListHelmAppReleases(ctx context.Context, app *dbmodel.Application) ([]*model.HelmAppRelease, error) {
// only for helm app
if app.AppType != model.AppTypeHelm {
return nil, nil
}
nctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
releases, err := a.statusCli.ListHelmAppRelease(nctx, &pb.AppReq{
AppId: app.AppID,
})
if err != nil {
return nil, err
}
var result []*model.HelmAppRelease
for _, rel := range releases.HelmAppRelease {
result = append(result, &model.HelmAppRelease{
Revision: int(rel.Revision),
Updated: rel.Updated,
Status: rel.Status,
Chart: rel.Chart,
AppVersion: rel.AppVersion,
Description: rel.Description,
})
}
return result, nil
}
// SyncComponents -
2021-06-19 19:41:28 +08:00
func (a *ApplicationAction) SyncComponents(app *dbmodel.Application, components []*model.Component, deleteComponentIDs []string) error {
return db.GetManager().DB().Transaction(func(tx *gorm.DB) error {
if err := GetServiceManager().SyncComponentBase(tx, app, components); err != nil {
return err
}
if err := GetGatewayHandler().SyncHTTPRules(tx, components); err != nil {
return err
}
2021-07-30 17:53:45 +08:00
if err := GetGatewayHandler().SyncRuleConfigs(tx, components); err != nil {
return err
}
if err := GetGatewayHandler().SyncTCPRules(tx, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentMonitors(tx, app, components); err != nil {
return err
}
2021-06-15 20:04:13 +08:00
if err := GetServiceManager().SyncComponentPlugins(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentPorts(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentRelations(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentEnvs(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentVolumeRels(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentVolumes(tx, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentConfigFiles(tx, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentProbes(tx, components); err != nil {
return err
}
if err := GetApplicationHandler().SyncComponentConfigGroupRels(tx, app, components); err != nil {
return err
}
if err := GetServiceManager().SyncComponentLabels(tx, components); err != nil {
return err
}
2021-06-19 19:41:28 +08:00
if err := GetServiceManager().SyncComponentScaleRules(tx, components); err != nil {
return err
}
2021-06-30 20:54:11 +08:00
if err := GetServiceManager().SyncComponentEndpoints(tx, components); err != nil {
return err
}
2021-06-19 19:41:28 +08:00
if len(deleteComponentIDs) != 0 {
return a.deleteByComponentIDs(tx, app, deleteComponentIDs)
}
return nil
})
}
2021-06-19 19:41:28 +08:00
func (a *ApplicationAction) deleteByComponentIDs(tx *gorm.DB, app *dbmodel.Application, componentIDs []string) error {
if err := db.GetManager().TenantServiceDaoTransactions(tx).DeleteByComponentIDs(app.TenantID, app.AppID, componentIDs); err != nil {
return err
}
if err := db.GetManager().HTTPRuleDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TCPRuleDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceMonitorDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServicesStreamPluginPortDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantPluginVersionConfigDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServicePluginRelationDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantPluginVersionENVDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServicesPortDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceRelationDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceEnvVarDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceMountRelationDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceVolumeDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceConfigFileDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().ServiceProbeDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().AppConfigGroupServiceDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
if err := db.GetManager().TenantServiceLabelDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
2021-06-30 20:54:11 +08:00
if err := db.GetManager().ThirdPartySvcDiscoveryCfgDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
2021-06-19 19:41:28 +08:00
autoScaleRules, err := db.GetManager().TenantServceAutoscalerRulesDaoTransactions(tx).ListByComponentIDs(componentIDs)
if err != nil {
return err
}
var autoScaleRuleIDs []string
for _, rule := range autoScaleRules {
autoScaleRuleIDs = append(autoScaleRuleIDs, rule.RuleID)
}
if err = db.GetManager().TenantServceAutoscalerRulesDaoTransactions(tx).DeleteByComponentIDs(componentIDs); err != nil {
return err
}
return db.GetManager().TenantServceAutoscalerRuleMetricsDaoTransactions(tx).DeleteByRuleIDs(autoScaleRuleIDs)
}
2021-07-22 16:01:08 +08:00
// ListAppStatuses -
func (a *ApplicationAction) ListAppStatuses(ctx context.Context, appIDs []string) ([]*model.AppStatus, error) {
2021-07-22 19:49:22 +08:00
var resp []*model.AppStatus
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
appStatuses, err := a.statusCli.ListAppStatuses(ctx, &pb.AppStatusesReq{
AppIds: appIDs,
})
2021-07-22 16:01:08 +08:00
if err != nil {
return nil, err
}
2021-07-22 19:49:22 +08:00
for _, appStatus := range appStatuses.AppStatuses {
diskUsage := a.getDiskUsage(appStatus.AppId)
2021-07-22 16:01:08 +08:00
var cpu *int64
2021-07-22 19:49:22 +08:00
if appStatus.SetCPU {
cpu = commonutil.Int64(appStatus.Cpu)
2021-07-22 16:01:08 +08:00
}
var memory *int64
2021-07-22 19:49:22 +08:00
if appStatus.SetMemory {
memory = commonutil.Int64(appStatus.Memory)
2021-07-22 16:01:08 +08:00
}
2021-07-22 19:49:22 +08:00
resp = append(resp, &model.AppStatus{
Status: appStatus.Status,
2021-07-22 16:01:08 +08:00
CPU: cpu,
Memory: memory,
Disk: int64(diskUsage),
2021-07-22 19:49:22 +08:00
Phase: appStatus.Phase,
Overrides: appStatus.Overrides,
Version: appStatus.Version,
AppID: appStatus.AppId,
AppName: appStatus.AppName,
2021-07-22 16:01:08 +08:00
})
}
2021-07-22 19:49:22 +08:00
return resp, nil
2021-07-22 16:01:08 +08:00
}
2021-11-11 09:55:17 +08:00
// CheckGovernanceMode Check whether the governance mode can be switched
func (a *ApplicationAction) CheckGovernanceMode(ctx context.Context, governanceMode string) error {
if !governance_mode.IsGovernanceModeValid(governanceMode) {
return bcode.ErrInvalidGovernanceMode
}
mode, err := governance_mode.NewAppGoveranceModeHandler(governanceMode, a.kubeClient)
if err != nil {
return err
}
if !mode.IsInstalledControlPlane() {
return bcode.ErrControlPlaneNotInstall
}
return nil
}