mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-14 05:16:49 +00:00
* Feat: add the rbac data model Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add some api about the project Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add CRUD about the project and the project user Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add CRUD about the role and perm check filter function Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: update swagger config Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add default roles and perm policies Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add perm check filter for all webservice Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: change the method that find project name Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: query applications and envs by user perm Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support get login user info Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: change default permissions Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: change PermPolicy to Permission Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add some unit test and fix the e2e test error Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: change some comment word Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e api path error Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
240 lines
7.6 KiB
Go
240 lines
7.6 KiB
Go
/*
|
|
Copyright 2022 The KubeVela Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package sync
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
|
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
|
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
|
v1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
|
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
|
"github.com/oam-dev/kubevela/pkg/utils"
|
|
)
|
|
|
|
// StoreProject will create project for synced application
|
|
func StoreProject(ctx context.Context, name string, ds datastore.DataStore, projectUsecase usecase.ProjectUsecase) error {
|
|
err := ds.Get(ctx, &model.Project{Name: name})
|
|
if err == nil {
|
|
// it means the record already exists, don't need to add anything
|
|
return nil
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
if projectUsecase != nil {
|
|
_, err := projectUsecase.CreateProject(ctx, v1.CreateProjectRequest{
|
|
Name: name,
|
|
Alias: strings.Title(name),
|
|
Owner: model.DefaultAdminUserName,
|
|
Description: model.AutoGenProj})
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StoreAppMeta will sync application metadata from CR to datastore
|
|
func StoreAppMeta(ctx context.Context, app *model.DataStoreApp, ds datastore.DataStore) error {
|
|
err := ds.Get(ctx, &model.Application{Name: app.AppMeta.Name})
|
|
if err == nil {
|
|
// it means the record already exists
|
|
return ds.Put(ctx, app.AppMeta)
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
return ds.Add(ctx, app.AppMeta)
|
|
}
|
|
|
|
// StoreEnv will sync application namespace from CR to datastore env, one namespace belongs to one env
|
|
func StoreEnv(ctx context.Context, app *model.DataStoreApp, ds datastore.DataStore) error {
|
|
curEnv := &model.Env{Name: app.Env.Name}
|
|
err := ds.Get(ctx, curEnv)
|
|
if err == nil {
|
|
// it means the record already exists, compare the targets
|
|
if utils.EqualSlice(curEnv.Targets, app.Env.Targets) {
|
|
return nil
|
|
}
|
|
return ds.Put(ctx, app.Env)
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
return ds.Add(ctx, app.Env)
|
|
}
|
|
|
|
// StoreEnvBinding will add envbinding for application CR one application one envbinding
|
|
func StoreEnvBinding(ctx context.Context, eb *model.EnvBinding, ds datastore.DataStore) error {
|
|
err := ds.Get(ctx, eb)
|
|
if err == nil {
|
|
// it means the record already exists, don't need to add anything
|
|
return nil
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
return ds.Add(ctx, eb)
|
|
}
|
|
|
|
// StoreComponents will sync application components from CR to datastore
|
|
func StoreComponents(ctx context.Context, appPrimaryKey string, expComps []*model.ApplicationComponent, ds datastore.DataStore) error {
|
|
|
|
// list the existing components in datastore
|
|
originComps, err := ds.List(ctx, &model.ApplicationComponent{AppPrimaryKey: appPrimaryKey}, &datastore.ListOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var originCompNames []string
|
|
for _, entity := range originComps {
|
|
comp := entity.(*model.ApplicationComponent)
|
|
originCompNames = append(originCompNames, comp.Name)
|
|
}
|
|
|
|
var targetCompNames []string
|
|
for _, comp := range expComps {
|
|
targetCompNames = append(targetCompNames, comp.Name)
|
|
}
|
|
|
|
_, readyToDelete, readyToAdd := utils.ThreeWaySliceCompare(originCompNames, targetCompNames)
|
|
|
|
// delete the components that not belongs to the new app
|
|
for _, entity := range originComps {
|
|
comp := entity.(*model.ApplicationComponent)
|
|
// we only compare for components that automatically generated by sync process.
|
|
if comp.Creator != model.AutoGenComp {
|
|
continue
|
|
}
|
|
if !utils.StringsContain(readyToDelete, comp.Name) {
|
|
continue
|
|
}
|
|
if err := ds.Delete(ctx, comp); err != nil {
|
|
if errors.Is(err, datastore.ErrRecordNotExist) {
|
|
continue
|
|
}
|
|
log.Logger.Warnf("delete comp %s for app %s failure %s", comp.Name, appPrimaryKey, err.Error())
|
|
}
|
|
}
|
|
|
|
// add or update new app's components for datastore
|
|
for _, comp := range expComps {
|
|
if utils.StringsContain(readyToAdd, comp.Name) {
|
|
err = ds.Add(ctx, comp)
|
|
} else {
|
|
err = ds.Put(ctx, comp)
|
|
}
|
|
if err != nil {
|
|
log.Logger.Warnf("convert comp %s for app %s into datastore failure %s", comp.Name, utils.Sanitize(appPrimaryKey), err.Error())
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StorePolicy will add/update/delete policies, we don't delete ref policy
|
|
func StorePolicy(ctx context.Context, appPrimaryKey string, expPolicies []*model.ApplicationPolicy, ds datastore.DataStore) error {
|
|
// list the existing policies for this app in datastore
|
|
originPolicies, err := ds.List(ctx, &model.ApplicationPolicy{AppPrimaryKey: appPrimaryKey}, &datastore.ListOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var originPolicyNames []string
|
|
for _, entity := range originPolicies {
|
|
plc := entity.(*model.ApplicationPolicy)
|
|
originPolicyNames = append(originPolicyNames, plc.Name)
|
|
}
|
|
|
|
var targetPLCNames []string
|
|
for _, plc := range expPolicies {
|
|
targetPLCNames = append(targetPLCNames, plc.Name)
|
|
}
|
|
|
|
_, readyToDelete, readyToAdd := utils.ThreeWaySliceCompare(originPolicyNames, targetPLCNames)
|
|
|
|
// delete the components that not belongs to the new app
|
|
for _, entity := range originPolicies {
|
|
plc := entity.(*model.ApplicationPolicy)
|
|
// we only compare for policies that automatically generated by sync process
|
|
// and the policy should not be ref ones.
|
|
|
|
if plc.Creator != model.AutoGenPolicy {
|
|
continue
|
|
}
|
|
if !utils.StringsContain(readyToDelete, plc.Name) {
|
|
continue
|
|
}
|
|
if err := ds.Delete(ctx, plc); err != nil {
|
|
if errors.Is(err, datastore.ErrRecordNotExist) {
|
|
continue
|
|
}
|
|
log.Logger.Warnf("delete policy %s for app %s failure %s", plc.Name, appPrimaryKey, err.Error())
|
|
}
|
|
}
|
|
|
|
// add or update new app's policies for datastore
|
|
for _, plc := range expPolicies {
|
|
if utils.StringsContain(readyToAdd, plc.Name) {
|
|
err = ds.Add(ctx, plc)
|
|
} else {
|
|
err = ds.Put(ctx, plc)
|
|
}
|
|
if err != nil {
|
|
log.Logger.Warnf("convert policy %s for app %s into datastore failure %s", plc.Name, utils.Sanitize(appPrimaryKey), err.Error())
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StoreWorkflow will sync workflow application CR to datastore, it updates the only one workflow from the application with specified name
|
|
func StoreWorkflow(ctx context.Context, dsApp *model.DataStoreApp, ds datastore.DataStore) error {
|
|
err := ds.Get(ctx, &model.Workflow{AppPrimaryKey: dsApp.AppMeta.Name, Name: dsApp.Workflow.Name})
|
|
if err == nil {
|
|
// it means the record already exists, update it
|
|
return ds.Put(ctx, dsApp.Workflow)
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
return ds.Add(ctx, dsApp.Workflow)
|
|
}
|
|
|
|
// StoreTargets will sync targets from application CR to datastore
|
|
func StoreTargets(ctx context.Context, dsApp *model.DataStoreApp, ds datastore.DataStore) error {
|
|
for _, t := range dsApp.Targets {
|
|
err := ds.Get(ctx, t)
|
|
if err == nil {
|
|
continue
|
|
}
|
|
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
|
// other database error, return it
|
|
return err
|
|
}
|
|
if err = ds.Add(ctx, t); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|