mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: supports multiple difference compare modes (#4334)
* Feat: supports multiple difference alignment modes Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: change field name Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
)
|
||||
|
||||
@@ -95,3 +96,26 @@ func DeleteApplicationEnvPolicies(ctx context.Context, store datastore.DataStore
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetApplicationRevision get the application revision
|
||||
// If the version is empty, will query the latest revision of the application
|
||||
func GetApplicationRevision(ctx context.Context, store datastore.DataStore, appName, version string) (*model.ApplicationRevision, error) {
|
||||
ar := &model.ApplicationRevision{AppPrimaryKey: appName}
|
||||
if version != "" {
|
||||
ar.Version = version
|
||||
}
|
||||
revisions, err := store.List(ctx, ar, &datastore.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 1,
|
||||
SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}},
|
||||
})
|
||||
if err != nil || len(revisions) == 0 {
|
||||
return nil, bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
latestRevisionRaw := revisions[0]
|
||||
latestRevision, ok := latestRevisionRaw.(*model.ApplicationRevision)
|
||||
if !ok {
|
||||
return nil, errors.New("convert application revision error")
|
||||
}
|
||||
return latestRevision, nil
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ type ApplicationService interface {
|
||||
DetailRevision(ctx context.Context, appName, revisionName string) (*apisv1.DetailRevisionResponse, error)
|
||||
Statistics(ctx context.Context, app *model.Application) (*apisv1.ApplicationStatisticsResponse, error)
|
||||
ListRecords(ctx context.Context, appName string) (*apisv1.ListWorkflowRecordsResponse, error)
|
||||
CompareAppWithLatestRevision(ctx context.Context, app *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error)
|
||||
CompareApp(ctx context.Context, app *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error)
|
||||
ResetAppToLatestRevision(ctx context.Context, appName string) (*apisv1.AppResetResponse, error)
|
||||
DryRunAppOrRevision(ctx context.Context, app *model.Application, dryRunReq apisv1.AppDryRunReq) (*apisv1.AppDryRunResponse, error)
|
||||
CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
|
||||
@@ -295,6 +295,23 @@ func (c *applicationServiceImpl) GetApplicationStatus(ctx context.Context, appmo
|
||||
return &app.Status, nil
|
||||
}
|
||||
|
||||
// GetApplicationStatus get application CR from controller cluster
|
||||
func (c *applicationServiceImpl) GetApplicationCRInEnv(ctx context.Context, appmodel *model.Application, envName string) (*v1beta1.Application, error) {
|
||||
var app v1beta1.Application
|
||||
env, err := c.EnvService.GetEnv(ctx, envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.KubeClient.Get(ctx, types.NamespacedName{Namespace: env.Namespace, Name: appmodel.GetAppNameForSynced()}, &app)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
// GetApplicationCR get application CR in cluster
|
||||
func (c *applicationServiceImpl) GetApplicationCR(ctx context.Context, appModel *model.Application) (*v1beta1.ApplicationList, error) {
|
||||
var apps v1beta1.ApplicationList
|
||||
@@ -629,7 +646,7 @@ func (c *applicationServiceImpl) Deploy(ctx context.Context, app *model.Applicat
|
||||
// TODO: rollback to handle all the error case
|
||||
// step1: Render oam application
|
||||
version := utils.GenerateVersion("")
|
||||
oamApp, err := c.renderOAMApplication(ctx, app, req.WorkflowName, version)
|
||||
oamApp, err := c.renderOAMApplication(ctx, app, req.WorkflowName, "", version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -770,7 +787,7 @@ func (c *applicationServiceImpl) syncConfigs4Application(ctx context.Context, ap
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appModel *model.Application, reqWorkflowName, version string) (*v1beta1.Application, error) {
|
||||
func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appModel *model.Application, reqWorkflowName, envName, version string) (*v1beta1.Application, error) {
|
||||
// Priority 1 uses the requested workflow as release .
|
||||
// Priority 2 uses the default workflow as release .
|
||||
var workflow *model.Workflow
|
||||
@@ -786,14 +803,15 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if workflow == nil || workflow.EnvName == "" {
|
||||
return nil, bcode.ErrWorkflowNotExist
|
||||
if workflow != nil {
|
||||
envName = workflow.EnvName
|
||||
}
|
||||
envbinding, err := c.EnvBindingService.GetEnvBinding(ctx, appModel, workflow.EnvName)
|
||||
|
||||
envbinding, err := c.EnvBindingService.GetEnvBinding(ctx, appModel, envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env, err := c.EnvService.GetEnv(ctx, workflow.EnvName)
|
||||
env, err := c.EnvService.GetEnv(ctx, envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -896,25 +914,25 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
}
|
||||
app.Spec.Policies = append(app.Spec.Policies, appPolicy)
|
||||
}
|
||||
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var workflowStep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
if workflow != nil {
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var workflowStep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
}
|
||||
if step.Properties != nil {
|
||||
workflowStep.Properties = step.Properties.RawExtension()
|
||||
}
|
||||
steps = append(steps, workflowStep)
|
||||
}
|
||||
if step.Properties != nil {
|
||||
workflowStep.Properties = step.Properties.RawExtension()
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
}
|
||||
steps = append(steps, workflowStep)
|
||||
}
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
@@ -1378,50 +1396,101 @@ func (c *applicationServiceImpl) Statistics(ctx context.Context, app *model.Appl
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CompareAppWithLatestRevision compare application with last revision
|
||||
func (c *applicationServiceImpl) CompareAppWithLatestRevision(ctx context.Context, appModel *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error) {
|
||||
var reqWorkflowName string
|
||||
if compareReq.Env != "" {
|
||||
reqWorkflowName = repository.ConvertWorkflowName(compareReq.Env)
|
||||
}
|
||||
newApp, err := c.renderOAMApplication(ctx, appModel, reqWorkflowName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ignoreSomeParams(newApp)
|
||||
newAppBytes, err := yaml.Marshal(newApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// CompareApp compare application
|
||||
func (c *applicationServiceImpl) CompareApp(ctx context.Context, appModel *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error) {
|
||||
var base, compareTarget *v1beta1.Application
|
||||
var err error
|
||||
var envNameByRevision string
|
||||
switch {
|
||||
case compareReq.CompareLatestWithRunning != nil:
|
||||
base, err = c.renderOAMApplication(ctx, appModel, "", compareReq.CompareLatestWithRunning.Env, "")
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to build the latest application %s", err.Error())
|
||||
break
|
||||
}
|
||||
case compareReq.CompareRevisionWithRunning != nil || compareReq.CompareRevisionWithLatest != nil:
|
||||
var revision = ""
|
||||
if compareReq.CompareRevisionWithRunning != nil {
|
||||
revision = compareReq.CompareRevisionWithRunning.Revision
|
||||
}
|
||||
if compareReq.CompareRevisionWithLatest != nil {
|
||||
revision = compareReq.CompareRevisionWithLatest.Revision
|
||||
}
|
||||
base, envNameByRevision, err = c.getAppModelFromRevision(ctx, appModel.Name, revision)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to get the app model from the revision %s", err.Error())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
oldApp, err := c.getAppFromLatestRevision(ctx, appModel.Name, compareReq.Env, "")
|
||||
if err != nil {
|
||||
if errors.Is(err, bcode.ErrApplicationRevisionNotExist) {
|
||||
return &apisv1.AppCompareResponse{IsDiff: false, NewAppYAML: string(newAppBytes)}, nil
|
||||
switch {
|
||||
case compareReq.CompareLatestWithRunning != nil || compareReq.CompareRevisionWithRunning != nil:
|
||||
var envName string
|
||||
if compareReq.CompareLatestWithRunning != nil {
|
||||
envName = compareReq.CompareLatestWithRunning.Env
|
||||
}
|
||||
if compareReq.CompareRevisionWithRunning != nil {
|
||||
envName = envNameByRevision
|
||||
}
|
||||
if envName == "" {
|
||||
break
|
||||
}
|
||||
compareTarget, err = c.GetApplicationCRInEnv(ctx, appModel, envName)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to query the application CR %s", err.Error())
|
||||
break
|
||||
}
|
||||
case compareReq.CompareRevisionWithLatest != nil:
|
||||
compareTarget, err = c.renderOAMApplication(ctx, appModel, "", envNameByRevision, "")
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to build the latest application %s", err.Error())
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ignoreSomeParams(oldApp)
|
||||
oldAppBytes, err := yaml.Marshal(oldApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
var baseAppBytes, targetAppBytes []byte
|
||||
|
||||
if base != nil {
|
||||
ignoreSomeParams(base)
|
||||
baseAppBytes, err = yaml.Marshal(base)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if compareTarget != nil {
|
||||
ignoreSomeParams(compareTarget)
|
||||
targetAppBytes, err = yaml.Marshal(compareTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
compareResponse := &apisv1.AppCompareResponse{IsDiff: true, BaseAppYAML: string(baseAppBytes), TargetAppYAML: string(targetAppBytes)}
|
||||
|
||||
if base == nil || compareTarget == nil {
|
||||
return compareResponse, nil
|
||||
}
|
||||
|
||||
args := common2.Args{
|
||||
Schema: common2.Scheme,
|
||||
}
|
||||
_ = args.SetConfig(c.KubeConfig)
|
||||
args.SetClient(c.KubeClient)
|
||||
diffResult, buff, err := compare(ctx, args, newApp, oldApp)
|
||||
diffResult, buff, err := compare(ctx, args, compareTarget, base)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to compare the app %s", err.Error())
|
||||
return &apisv1.AppCompareResponse{IsDiff: false, NewAppYAML: string(newAppBytes), OldAppYAML: string(oldAppBytes)}, err
|
||||
compareResponse.IsDiff = false
|
||||
return compareResponse, nil
|
||||
}
|
||||
return &apisv1.AppCompareResponse{IsDiff: diffResult.DiffType != "", DiffReport: buff.String(), NewAppYAML: string(newAppBytes), OldAppYAML: string(oldAppBytes)}, nil
|
||||
compareResponse.IsDiff = diffResult.DiffType != ""
|
||||
compareResponse.DiffReport = buff.String()
|
||||
return compareResponse, nil
|
||||
}
|
||||
|
||||
// ResetAppToLatestRevision reset app's component to last revision
|
||||
func (c *applicationServiceImpl) ResetAppToLatestRevision(ctx context.Context, appName string) (*apisv1.AppResetResponse, error) {
|
||||
targetApp, err := c.getAppFromLatestRevision(ctx, appName, "", "")
|
||||
targetApp, _, err := c.getAppModelFromRevision(ctx, appName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1433,16 +1502,12 @@ func (c *applicationServiceImpl) DryRunAppOrRevision(ctx context.Context, appMod
|
||||
var app *v1beta1.Application
|
||||
var err error
|
||||
if dryRunReq.DryRunType == "APP" {
|
||||
var reqWorkflowName string
|
||||
if dryRunReq.Env != "" {
|
||||
reqWorkflowName = repository.ConvertWorkflowName(dryRunReq.Env)
|
||||
}
|
||||
app, err = c.renderOAMApplication(ctx, appModel, reqWorkflowName, "")
|
||||
app, err = c.renderOAMApplication(ctx, appModel, dryRunReq.Workflow, dryRunReq.Env, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
app, err = c.getAppFromLatestRevision(ctx, dryRunReq.AppName, dryRunReq.Env, dryRunReq.Version)
|
||||
app, _, err = c.getAppModelFromRevision(ctx, dryRunReq.AppName, dryRunReq.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1470,33 +1535,16 @@ func genWebhookToken() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) getAppFromLatestRevision(ctx context.Context, appName string, envName string, version string) (*v1beta1.Application, error) {
|
||||
|
||||
ar := &model.ApplicationRevision{AppPrimaryKey: appName}
|
||||
if envName != "" {
|
||||
ar.EnvName = envName
|
||||
}
|
||||
if version != "" {
|
||||
ar.Version = version
|
||||
}
|
||||
revisions, err := c.Store.List(ctx, ar, &datastore.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 1,
|
||||
SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}},
|
||||
})
|
||||
if err != nil || len(revisions) == 0 {
|
||||
return nil, bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
latestRevisionRaw := revisions[0]
|
||||
latestRevision, ok := latestRevisionRaw.(*model.ApplicationRevision)
|
||||
if !ok {
|
||||
return nil, errors.New("convert application revision error")
|
||||
func (c *applicationServiceImpl) getAppModelFromRevision(ctx context.Context, appName string, version string) (*v1beta1.Application, string, error) {
|
||||
latestRevision, err := repository.GetApplicationRevision(ctx, c.Store, appName, version)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
oldApp := &v1beta1.Application{}
|
||||
if err := yaml.Unmarshal([]byte(latestRevision.ApplyAppConfig), oldApp); err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
return oldApp, nil
|
||||
return oldApp, latestRevision.EnvName, nil
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) resetApp(ctx context.Context, targetApp *v1beta1.Application) (*apisv1.AppResetResponse, error) {
|
||||
@@ -1605,21 +1653,23 @@ func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Applica
|
||||
// ignoreSomeParams ignore some parameters before comparing the app changes.
|
||||
// ignore the workflow spec
|
||||
func ignoreSomeParams(o *v1beta1.Application) {
|
||||
// set default
|
||||
o.ResourceVersion = ""
|
||||
o.Spec.Workflow = nil
|
||||
newAnnotations := map[string]string{}
|
||||
annotations := o.GetAnnotations()
|
||||
for k, v := range annotations {
|
||||
if k == oam.AnnotationDeployVersion || k == oam.AnnotationPublishVersion || k == "kubectl.kubernetes.io/last-applied-configuration" {
|
||||
continue
|
||||
}
|
||||
newAnnotations[k] = v
|
||||
}
|
||||
o.SetAnnotations(newAnnotations)
|
||||
var defaultApplication = v1beta1.Application{}
|
||||
// only compare the spec without the workflow
|
||||
defaultApplication.Spec = o.Spec
|
||||
defaultApplication.Spec.Workflow = nil
|
||||
defaultApplication.Name = o.Name
|
||||
defaultApplication.Namespace = o.Namespace
|
||||
|
||||
sort.Slice(defaultApplication.Spec.Policies, func(i, j int) bool {
|
||||
return defaultApplication.Spec.Policies[i].Name < defaultApplication.Spec.Policies[j].Name
|
||||
})
|
||||
sort.Slice(defaultApplication.Spec.Components, func(i, j int) bool {
|
||||
return defaultApplication.Spec.Components[i].Name < defaultApplication.Spec.Components[j].Name
|
||||
})
|
||||
*o = defaultApplication
|
||||
}
|
||||
|
||||
func compare(ctx context.Context, c common2.Args, newApp *v1beta1.Application, oldApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
func compare(ctx context.Context, c common2.Args, targetApp *v1beta1.Application, baseApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
var buff = bytes.Buffer{}
|
||||
_, err := c.GetClient()
|
||||
if err != nil {
|
||||
@@ -1643,7 +1693,7 @@ func compare(ctx context.Context, c common2.Args, newApp *v1beta1.Application, o
|
||||
return nil, buff, err
|
||||
}
|
||||
liveDiffOption := dryrun.NewLiveDiffOption(client, config, dm, pd, objs)
|
||||
diffResult, err := liveDiffOption.DiffApps(ctx, newApp, oldApp)
|
||||
diffResult, err := liveDiffOption.DiffApps(ctx, baseApp, targetApp)
|
||||
if err != nil {
|
||||
return nil, buff, err
|
||||
}
|
||||
|
||||
@@ -478,8 +478,12 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(resp.Total).Should(Equal(int64(3)))
|
||||
})
|
||||
|
||||
It("Test CompareAppWithLatestRevision function", func() {
|
||||
|
||||
It("Test CompareApp function", func() {
|
||||
check := func(compareResponse *v1.AppCompareResponse, isDiff bool) {
|
||||
Expect(cmp.Diff(compareResponse.BaseAppYAML, "")).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.TargetAppYAML, "")).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, isDiff)).Should(BeEmpty())
|
||||
}
|
||||
appModel, err := appService.GetApplication(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = appService.Deploy(context.TODO(), appModel, v1.ApplicationDeployRequest{WorkflowName: repository.ConvertWorkflowName("app-dev")})
|
||||
@@ -488,23 +492,40 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("compare when app not change, should return false")
|
||||
compareResponse, err := appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
compareResponse, err := appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
check(compareResponse, false)
|
||||
|
||||
By("compare when app not change and env not empty, should return false")
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{Env: "app-dev"})
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
check(compareResponse, false)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
|
||||
By("compare when app add env, not change, should return false")
|
||||
_, err = envService.CreateEnv(context.TODO(), v1.CreateEnvRequest{Name: "app-prod", Namespace: "envnsprod", Targets: []string{defaultTarget}, Project: "app-prod"})
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = envBindingService.CreateEnvBinding(context.TODO(), appModel, v1.CreateApplicationEnvbindingRequest{EnvBinding: v1.EnvBinding{Name: "app-prod"}})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-prod",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.TargetAppYAML, "")).Should(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.BaseAppYAML, "")).ShouldNot(BeEmpty())
|
||||
|
||||
By("compare when app's env add target, should return true")
|
||||
_, err = targetService.CreateTarget(context.TODO(), v1.CreateTargetRequest{Name: "dev-target1", Project: appModel.Project, Cluster: &v1.ClusterTarget{ClusterName: "local", Namespace: "dev-target1"}})
|
||||
@@ -515,9 +536,13 @@ var _ = Describe("Test application service function", func() {
|
||||
Targets: []string{defaultTarget, "dev-target1"},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
check(compareResponse, true)
|
||||
|
||||
By("compare when update app's trait, should return true")
|
||||
// reset app config
|
||||
@@ -529,11 +554,21 @@ var _ = Describe("Test application service function", func() {
|
||||
Description: "description",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
|
||||
By("compare when update component's target after app deployed ,should return ture")
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
|
||||
By("compare when update component's target after app deployed ,should return true")
|
||||
// reset app config
|
||||
_, err = appService.ResetAppToLatestRevision(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -545,9 +580,49 @@ var _ = Describe("Test application service function", func() {
|
||||
Properties: &newProperties,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
|
||||
By("compare when changed the application CR, should return true")
|
||||
|
||||
appCR, err := appService.GetApplicationCRInEnv(context.TODO(), appModel, "app-dev")
|
||||
Expect(err).Should(BeNil())
|
||||
appCR.Spec.Components[0].Properties = &runtime.RawExtension{Raw: []byte("{\"exposeType\":\"NodePort\",\"image\":\"nginx:222\",\"imagePullPolicy\":\"Always\"}")}
|
||||
err = k8sClient.Update(context.TODO(), appCR)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
err = envBindingService.ApplicationEnvRecycle(context.TODO(), &model.Application{Name: testApp}, &model.EnvBinding{Name: "app-dev"})
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
@@ -23,6 +23,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/event/sync/convert"
|
||||
@@ -98,8 +101,17 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
targetNames = append(targetNames, name)
|
||||
}
|
||||
}
|
||||
var namespace corev1.Namespace
|
||||
envName := model.AutoGenEnvNamePrefix + targetApp.Namespace
|
||||
// Get the env name from the label of namespace
|
||||
// If the namespace created by `vela env init`
|
||||
if c.cli.Get(ctx, types.NamespacedName{Name: targetApp.Namespace}, &namespace) == nil {
|
||||
if env, ok := namespace.Labels[oam.LabelNamespaceOfEnvName]; ok {
|
||||
envName = env
|
||||
}
|
||||
}
|
||||
dsApp.Env = &model.Env{
|
||||
Name: model.AutoGenEnvNamePrefix + targetApp.Namespace,
|
||||
Name: envName,
|
||||
Namespace: targetApp.Namespace,
|
||||
Description: model.AutoGenDesc,
|
||||
Project: newProject,
|
||||
|
||||
@@ -549,8 +549,8 @@ func (c *applicationAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes(apis.ListWorkflowRecordsResponse{}))
|
||||
|
||||
ws.Route(ws.POST("/{appName}/compare").To(c.compareAppWithLatestRevision).
|
||||
Doc("compare application with env latest revision").
|
||||
ws.Route(ws.POST("/{appName}/compare").To(c.compareApp).
|
||||
Doc("compare application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("application", "compare")).
|
||||
Filter(c.appCheckFilter).
|
||||
@@ -1184,7 +1184,7 @@ func (c *applicationAPIInterface) listApplicationRecords(req *restful.Request, r
|
||||
}
|
||||
}
|
||||
|
||||
func (c *applicationAPIInterface) compareAppWithLatestRevision(req *restful.Request, res *restful.Response) {
|
||||
func (c *applicationAPIInterface) compareApp(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
// Verify the validity of parameters
|
||||
var compareReq apis.AppCompareReq
|
||||
@@ -1197,7 +1197,7 @@ func (c *applicationAPIInterface) compareAppWithLatestRevision(req *restful.Requ
|
||||
return
|
||||
}
|
||||
|
||||
base, err := c.ApplicationService.CompareAppWithLatestRevision(req.Request.Context(), app, compareReq)
|
||||
base, err := c.ApplicationService.CompareApp(req.Request.Context(), app, compareReq)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
|
||||
@@ -362,10 +362,10 @@ type ApplicationBase struct {
|
||||
|
||||
// AppCompareResponse application compare result
|
||||
type AppCompareResponse struct {
|
||||
IsDiff bool `json:"isDiff"`
|
||||
DiffReport string `json:"diffReport"`
|
||||
NewAppYAML string `json:"newAppYAML"`
|
||||
OldAppYAML string `json:"oldAppYAML"`
|
||||
IsDiff bool `json:"isDiff"`
|
||||
DiffReport string `json:"diffReport"`
|
||||
BaseAppYAML string `json:"baseAppYAML"`
|
||||
TargetAppYAML string `json:"targetAppYAML"`
|
||||
}
|
||||
|
||||
// AppResetResponse application reset result
|
||||
@@ -375,7 +375,26 @@ type AppResetResponse struct {
|
||||
|
||||
// AppCompareReq application compare req
|
||||
type AppCompareReq struct {
|
||||
Env string `json:"env"`
|
||||
CompareRevisionWithRunning *CompareRevisionWithRunningOption `json:"compareRevisionWithRunning,omitempty"`
|
||||
CompareRevisionWithLatest *CompareRevisionWithLatestOption `json:"compareRevisionWithLatest,omitempty"`
|
||||
CompareLatestWithRunning *CompareLatestWithRunningOption `json:"compareLatestWithRunning,omitempty"`
|
||||
}
|
||||
|
||||
// CompareRevisionWithRunningOption means compare the specified version with the application in cluster.
|
||||
type CompareRevisionWithRunningOption struct {
|
||||
// Revision, If not specified, means use the latest revision.
|
||||
Revision string `json:"revision" optional:"true"`
|
||||
}
|
||||
|
||||
// CompareRevisionWithLatestOption means compare the the specified version with the latest application configuration
|
||||
type CompareRevisionWithLatestOption struct {
|
||||
// Revision, If not specified, means use the latest revision.
|
||||
Revision string `json:"revision" optional:"true"`
|
||||
}
|
||||
|
||||
// CompareLatestWithRunningOption means compare the latest configuration with the app in cluster.
|
||||
type CompareLatestWithRunningOption struct {
|
||||
Env string `json:"env" validate:"required"`
|
||||
}
|
||||
|
||||
// AppDryRunReq application dry-run req
|
||||
@@ -383,6 +402,7 @@ type AppDryRunReq struct {
|
||||
AppName string `json:"appName"`
|
||||
DryRunType string `json:"dryRunType"`
|
||||
Env string `json:"env"`
|
||||
Workflow string `json:"workflow"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user