mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: support update component and query app statistics info (#2746)
* Feat: change swagger config * Feat: support update component and query app statistics info * Fix: fix workflow list bug * Fix: fix test bug * Fix: fix e2e test bug * Feat: change workflow api * Fix: fix app deploy e2e test bug * Fix: change e2e test * Fix: fix workflow bug * Fix: fix deploy bug * Fix: fix selector bug * Feat: support recycle env * Fix: debug e2e * Fix: fix e2e case bug Co-authored-by: barnettZQG <yiyun.pro>
This commit is contained in:
+718
-510
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -51,6 +52,7 @@ type WorkflowStep struct {
|
||||
OrderIndex int `json:"orderIndex"`
|
||||
Inputs common.StepInputs `json:"inputs,omitempty"`
|
||||
Outputs common.StepOutputs `json:"outputs,omitempty"`
|
||||
DependsOn []string `json:"dependsOn"`
|
||||
Properties *JSONStruct `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
@@ -61,7 +63,7 @@ func (w *Workflow) TableName() string {
|
||||
|
||||
// PrimaryKey return custom primary key
|
||||
func (w *Workflow) PrimaryKey() string {
|
||||
return w.Name
|
||||
return fmt.Sprintf("%s-%s", w.AppPrimaryKey, w.Name)
|
||||
}
|
||||
|
||||
// Index return custom primary key
|
||||
@@ -83,7 +85,7 @@ func (w *Workflow) Index() map[string]string {
|
||||
// WorkflowRecord is the workflow record database model
|
||||
type WorkflowRecord struct {
|
||||
Model
|
||||
WorkflowPrimaryKey string `json:"workflowPrimaryKey"`
|
||||
WorkflowName string `json:"workflowName"`
|
||||
AppPrimaryKey string `json:"appPrimaryKey"`
|
||||
RevisionPrimaryKey string `json:"revisionPrimaryKey"`
|
||||
Name string `json:"name"`
|
||||
@@ -113,8 +115,8 @@ func (w *WorkflowRecord) Index() map[string]string {
|
||||
if w.Namespace != "" {
|
||||
index["namespace"] = w.Namespace
|
||||
}
|
||||
if w.WorkflowPrimaryKey != "" {
|
||||
index["workflowPrimaryKey"] = w.WorkflowPrimaryKey
|
||||
if w.WorkflowName != "" {
|
||||
index["workflowPrimaryKey"] = w.WorkflowName
|
||||
}
|
||||
if w.AppPrimaryKey != "" {
|
||||
index["appPrimaryKey"] = w.AppPrimaryKey
|
||||
|
||||
@@ -39,6 +39,8 @@ var (
|
||||
CtxKeyDeliveryTarget = "delivery-target"
|
||||
// CtxKeyApplicationEnvBinding request context key of env binding
|
||||
CtxKeyApplicationEnvBinding = "envbinding-policy"
|
||||
// CtxKeyApplicationComponent request context key of component
|
||||
CtxKeyApplicationComponent = "component"
|
||||
)
|
||||
|
||||
// AddonPhase defines the phase of an addon
|
||||
@@ -283,6 +285,14 @@ type ApplicationStatusResponse struct {
|
||||
Status *common.AppStatus `json:"status"`
|
||||
}
|
||||
|
||||
// ApplicationStatisticsResponse application statistics response body
|
||||
type ApplicationStatisticsResponse struct {
|
||||
EnvCount int64 `json:"envCount"`
|
||||
DeliveryTargetCount int64 `json:"deliveryTargetCount"`
|
||||
RevisonCount int64 `json:"revisonCount"`
|
||||
WorkflowCount int64 `json:"workflowCount"`
|
||||
}
|
||||
|
||||
// CreateApplicationRequest create application request body
|
||||
type CreateApplicationRequest struct {
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
@@ -315,13 +325,15 @@ type EnvBinding struct {
|
||||
|
||||
// EnvBindingBase application env binding
|
||||
type EnvBindingBase struct {
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Alias string `json:"alias" validate:"checkalias" optional:"true"`
|
||||
Description string `json:"description,omitempty" optional:"true"`
|
||||
TargetNames []string `json:"targetNames"`
|
||||
ComponentSelector *ComponentSelector `json:"componentSelector" optional:"true"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Alias string `json:"alias" validate:"checkalias" optional:"true"`
|
||||
Description string `json:"description,omitempty" optional:"true"`
|
||||
TargetNames []string `json:"targetNames"`
|
||||
Targets []DeliveryTargetBase `json:"deliveryTargets,omitempty"`
|
||||
ComponentSelector *ComponentSelector `json:"componentSelector" optional:"true"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
AppDeployName string `json:"appDeployName"`
|
||||
}
|
||||
|
||||
// DetailEnvBindingResponse defines the response of env-binding details
|
||||
@@ -344,11 +356,10 @@ type ComponentSelector struct {
|
||||
// DetailApplicationResponse application detail
|
||||
type DetailApplicationResponse struct {
|
||||
ApplicationBase
|
||||
Policies []string `json:"policies"`
|
||||
EnvBindings []string `json:"envBindings"`
|
||||
Status string `json:"status"`
|
||||
ResourceInfo ApplicationResourceInfo `json:"resourceInfo"`
|
||||
WorkflowStatus []WorkflowStepStatus `json:"workflowStatus"`
|
||||
Policies []string `json:"policies"`
|
||||
EnvBindings []string `json:"envBindings"`
|
||||
Status string `json:"status"`
|
||||
ResourceInfo ApplicationResourceInfo `json:"resourceInfo"`
|
||||
}
|
||||
|
||||
// WorkflowStepStatus workflow step status model
|
||||
@@ -360,7 +371,7 @@ type WorkflowStepStatus struct {
|
||||
|
||||
// ApplicationResourceInfo application-level resource consumption statistics
|
||||
type ApplicationResourceInfo struct {
|
||||
ComponentNum int `json:"componentNum"`
|
||||
ComponentNum int64 `json:"componentNum"`
|
||||
// Others, such as: Memory、CPU、GPU、Storage
|
||||
}
|
||||
|
||||
@@ -398,6 +409,16 @@ type CreateComponentRequest struct {
|
||||
Traits []*CreateApplicationTraitRequest `json:"traits,omitempty" optional:"true"`
|
||||
}
|
||||
|
||||
// UpdateApplicationComponentRequest update component request body
|
||||
type UpdateApplicationComponentRequest struct {
|
||||
Alias *string `json:"alias" validate:"checkalias" optional:"true"`
|
||||
Description *string `json:"description" optional:"true"`
|
||||
Icon *string `json:"icon" optional:"true"`
|
||||
Labels *map[string]string `json:"labels,omitempty"`
|
||||
Properties *string `json:"properties,omitempty"`
|
||||
DependsOn *[]string `json:"dependsOn" optional:"true"`
|
||||
}
|
||||
|
||||
// DetailComponentResponse detail component response body
|
||||
type DetailComponentResponse struct {
|
||||
model.ApplicationComponent
|
||||
@@ -567,8 +588,6 @@ type WorkflowStep struct {
|
||||
// DetailWorkflowResponse detail workflow response
|
||||
type DetailWorkflowResponse struct {
|
||||
WorkflowBase
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
LastRecord *WorkflowRecord `json:"workflowRecord"`
|
||||
}
|
||||
|
||||
// ListWorkflowResponse list application workflows
|
||||
@@ -578,14 +597,15 @@ type ListWorkflowResponse struct {
|
||||
|
||||
// WorkflowBase workflow base model
|
||||
type WorkflowBase struct {
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Description string `json:"description"`
|
||||
Enable bool `json:"enable"`
|
||||
Default bool `json:"default"`
|
||||
EnvName string `json:"envName"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Description string `json:"description"`
|
||||
Enable bool `json:"enable"`
|
||||
Default bool `json:"default"`
|
||||
EnvName string `json:"envName"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
// ListWorkflowRecordsResponse list workflow execution record
|
||||
@@ -722,6 +742,7 @@ type DeliveryTargetBase struct {
|
||||
Variable map[string]interface{} `json:"variable,omitempty"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
AppNum int64 `json:"appNum,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationRevisionBase application revision base spec
|
||||
|
||||
@@ -18,7 +18,6 @@ package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
@@ -28,6 +27,8 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -68,10 +69,12 @@ type ApplicationUsecase interface {
|
||||
UpdateApplication(context.Context, *model.Application, apisv1.UpdateApplicationRequest) (*apisv1.ApplicationBase, error)
|
||||
DeleteApplication(ctx context.Context, app *model.Application) error
|
||||
Deploy(ctx context.Context, app *model.Application, req apisv1.ApplicationDeployRequest) (*apisv1.ApplicationDeployResponse, error)
|
||||
GetApplicationComponent(ctx context.Context, app *model.Application, componentName string) (*model.ApplicationComponent, error)
|
||||
ListComponents(ctx context.Context, app *model.Application, op apisv1.ListApplicationComponentOptions) ([]*apisv1.ComponentBase, error)
|
||||
AddComponent(ctx context.Context, app *model.Application, com apisv1.CreateComponentRequest) (*apisv1.ComponentBase, error)
|
||||
DetailComponent(ctx context.Context, app *model.Application, componentName string) (*apisv1.DetailComponentResponse, error)
|
||||
DeleteComponent(ctx context.Context, app *model.Application, componentName string) error
|
||||
UpdateComponent(ctx context.Context, app *model.Application, component *model.ApplicationComponent, req apisv1.UpdateApplicationComponentRequest) (*apisv1.ComponentBase, error)
|
||||
ListPolicies(ctx context.Context, app *model.Application) ([]*apisv1.PolicyBase, error)
|
||||
AddPolicy(ctx context.Context, app *model.Application, policy apisv1.CreatePolicyRequest) (*apisv1.PolicyBase, error)
|
||||
DetailPolicy(ctx context.Context, app *model.Application, policyName string) (*apisv1.DetailPolicyResponse, error)
|
||||
@@ -81,7 +84,8 @@ type ApplicationUsecase interface {
|
||||
DeleteApplicationTrait(ctx context.Context, app *model.Application, component *model.ApplicationComponent, traitType string) error
|
||||
UpdateApplicationTrait(ctx context.Context, app *model.Application, component *model.ApplicationComponent, traitType string, req apisv1.UpdateApplicationTraitRequest) (*apisv1.ApplicationTrait, error)
|
||||
ListRevisions(ctx context.Context, appName, envName, status string, page, pageSize int) (*apisv1.ListRevisionsResponse, error)
|
||||
DetailRevision(ctx context.Context, appName, revisionVersion string) (*apisv1.DetailRevisionResponse, error)
|
||||
DetailRevision(ctx context.Context, appName, revisionName string) (*apisv1.DetailRevisionResponse, error)
|
||||
Statistics(ctx context.Context, app *model.Application) (*apisv1.ApplicationStatisticsResponse, error)
|
||||
}
|
||||
|
||||
type applicationUsecaseImpl struct {
|
||||
@@ -163,7 +167,7 @@ func (c *applicationUsecaseImpl) DetailApplication(ctx context.Context, app *mod
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
components, err := c.ListComponents(ctx, app, apisv1.ListApplicationComponentOptions{})
|
||||
componentNum, err := c.ds.Count(ctx, &model.ApplicationComponent{AppPrimaryKey: app.PrimaryKey()}, &datastore.FilterOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -184,9 +188,8 @@ func (c *applicationUsecaseImpl) DetailApplication(ctx context.Context, app *mod
|
||||
Policies: policyNames,
|
||||
EnvBindings: envBindingNames,
|
||||
ResourceInfo: apisv1.ApplicationResourceInfo{
|
||||
ComponentNum: len(components),
|
||||
ComponentNum: componentNum,
|
||||
},
|
||||
WorkflowStatus: []apisv1.WorkflowStepStatus{},
|
||||
}
|
||||
return detail, nil
|
||||
}
|
||||
@@ -194,7 +197,7 @@ func (c *applicationUsecaseImpl) DetailApplication(ctx context.Context, app *mod
|
||||
// GetApplicationStatus get application status from controller cluster
|
||||
func (c *applicationUsecaseImpl) GetApplicationStatus(ctx context.Context, appmodel *model.Application, envName string) (*common.AppStatus, error) {
|
||||
var app v1beta1.Application
|
||||
err := c.kubeClient.Get(ctx, types.NamespacedName{Namespace: appmodel.Namespace, Name: converAppName(appmodel, envName)}, &app)
|
||||
err := c.kubeClient.Get(ctx, types.NamespacedName{Namespace: appmodel.Namespace, Name: converAppName(appmodel.Name, envName)}, &app)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
@@ -204,6 +207,27 @@ func (c *applicationUsecaseImpl) GetApplicationStatus(ctx context.Context, appmo
|
||||
return &app.Status, nil
|
||||
}
|
||||
|
||||
// GetApplicationCR get application cr in cluster
|
||||
func (c *applicationUsecaseImpl) GetApplicationCR(ctx context.Context, appmodel *model.Application) (*v1beta1.ApplicationList, error) {
|
||||
var apps v1beta1.ApplicationList
|
||||
selector := labels.NewSelector()
|
||||
re, err := labels.NewRequirement(oam.AnnotationAppName, selection.Equals, []string{appmodel.Name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector = selector.Add(*re)
|
||||
err = c.kubeClient.List(ctx, &apps, &client.ListOptions{
|
||||
LabelSelector: selector,
|
||||
})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return &apps, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &apps, nil
|
||||
}
|
||||
|
||||
// PublishApplicationTemplate publish app template
|
||||
func (c *applicationUsecaseImpl) PublishApplicationTemplate(ctx context.Context, app *model.Application) (*apisv1.ApplicationTemplateBase, error) {
|
||||
//TODO:
|
||||
@@ -247,13 +271,6 @@ func (c *applicationUsecaseImpl) CreateApplication(ctx context.Context, req apis
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if oamApp.Spec.Workflow != nil && len(oamApp.Spec.Workflow.Steps) > 0 {
|
||||
if err := c.saveApplicationWorkflow(ctx, &application, oamApp.Spec.Workflow.Steps, application.Name); err != nil {
|
||||
log.Logger.Errorf("save applictaion polocies failure,%s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// TODO Waiting for Spec.EnvBinding support
|
||||
}
|
||||
|
||||
// build-in create env binding
|
||||
@@ -301,46 +318,12 @@ func (c *applicationUsecaseImpl) genPolicyByEnv(ctx context.Context, app *model.
|
||||
}
|
||||
properties, err := model.NewJSONStructByStruct(envBindingSpec)
|
||||
if err != nil {
|
||||
return appPolicy, err
|
||||
return appPolicy, bcode.ErrInvalidProperties
|
||||
}
|
||||
appPolicy.Properties = properties.RawExtension()
|
||||
return appPolicy, nil
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) saveApplicationWorkflow(ctx context.Context, application *model.Application, workflowSteps []v1beta1.WorkflowStep, workflowName string) error {
|
||||
var steps []apisv1.WorkflowStep
|
||||
for _, step := range workflowSteps {
|
||||
var propertyStr string
|
||||
if step.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(step.Properties)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("workflow %s step %s properties is invalid %s", application.Name, step.Name, err.Error())
|
||||
continue
|
||||
}
|
||||
propertyStr = properties.JSON()
|
||||
}
|
||||
steps = append(steps, apisv1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
DependsOn: step.DependsOn,
|
||||
Properties: propertyStr,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
})
|
||||
}
|
||||
_, err := c.workflowUsecase.CreateWorkflow(ctx, application, apisv1.CreateWorkflowRequest{
|
||||
AppName: application.PrimaryKey(),
|
||||
Name: workflowName,
|
||||
Description: "Created automatically.",
|
||||
Steps: steps,
|
||||
Default: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) saveApplicationEnvBinding(ctx context.Context, app model.Application, envBindings []*apisv1.EnvBinding) error {
|
||||
err := c.envBindingUsecase.BatchCreateEnvBinding(ctx, &app, envBindings)
|
||||
if err != nil {
|
||||
@@ -495,7 +478,6 @@ func (c *applicationUsecaseImpl) converPolicyModelToBase(policy *model.Applicati
|
||||
|
||||
func (c *applicationUsecaseImpl) saveApplicationPolicy(ctx context.Context, app *model.Application, policys []v1beta1.AppPolicy) error {
|
||||
var policyModels []datastore.Entity
|
||||
var envbindingPolicy *model.ApplicationPolicy
|
||||
for _, policy := range policys {
|
||||
properties, err := model.NewJSONStruct(policy.Properties)
|
||||
if err != nil {
|
||||
@@ -510,26 +492,6 @@ func (c *applicationUsecaseImpl) saveApplicationPolicy(ctx context.Context, app
|
||||
}
|
||||
if policy.Type != string(EnvBindingPolicy) {
|
||||
policyModels = append(policyModels, appPolicy)
|
||||
} else {
|
||||
envbindingPolicy = appPolicy
|
||||
}
|
||||
}
|
||||
// If multiple configurations are configured, enable only the last one.
|
||||
if envbindingPolicy != nil {
|
||||
envbindingPolicy.Name = EnvBindingPolicyDefaultName
|
||||
policyModels = append(policyModels, envbindingPolicy)
|
||||
var envBindingSpec v1alpha1.EnvBindingSpec
|
||||
if err := json.Unmarshal([]byte(envbindingPolicy.Properties.JSON()), &envBindingSpec); err != nil {
|
||||
return fmt.Errorf("unmarshal env binding policy failure %w", err)
|
||||
}
|
||||
for _, env := range envBindingSpec.Envs {
|
||||
envBind := &model.EnvBinding{
|
||||
Name: env.Name,
|
||||
Description: "",
|
||||
}
|
||||
if env.Selector != nil {
|
||||
envBind.ComponentSelector = (*model.ComponentSelector)(env.Selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.ds.BatchAdd(ctx, policyModels)
|
||||
@@ -578,26 +540,30 @@ func (c *applicationUsecaseImpl) Deploy(ctx context.Context, app *model.Applicat
|
||||
return nil, err
|
||||
}
|
||||
configByte, _ := yaml.Marshal(oamApp)
|
||||
|
||||
workflow, err := c.workflowUsecase.GetWorkflow(ctx, app, oamApp.Annotations[oam.AnnotationWorkflowName])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// step2: check and create deploy event
|
||||
if !req.Force {
|
||||
var lastVersion = model.ApplicationRevision{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
EnvName: workflow.EnvName,
|
||||
}
|
||||
list, err := c.ds.List(ctx, &lastVersion, &datastore.ListOptions{PageSize: 1, Page: 1})
|
||||
list, err := c.ds.List(ctx, &lastVersion, &datastore.ListOptions{
|
||||
PageSize: 1, Page: 1, SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}}})
|
||||
if err != nil && !errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
log.Logger.Errorf("query app latest revision failure %s", err.Error())
|
||||
return nil, bcode.ErrDeployConflict
|
||||
}
|
||||
if len(list) > 0 && list[0].(*model.ApplicationRevision).Status != model.RevisionStatusComplete {
|
||||
log.Logger.Warnf("last app revision can not complete %s/%s", list[0].(*model.ApplicationRevision).AppPrimaryKey, list[0].(*model.ApplicationRevision).Version)
|
||||
return nil, bcode.ErrDeployConflict
|
||||
}
|
||||
}
|
||||
|
||||
workflow, err := c.workflowUsecase.GetWorkflow(ctx, oamApp.Annotations[oam.AnnotationWorkflowName])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var appRevision = &model.ApplicationRevision{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
Version: version,
|
||||
@@ -615,7 +581,7 @@ func (c *applicationUsecaseImpl) Deploy(ctx context.Context, app *model.Applicat
|
||||
return nil, err
|
||||
}
|
||||
// step3: create workflow record
|
||||
if err := c.workflowUsecase.CreateWorkflowRecord(ctx, oamApp); err != nil {
|
||||
if err := c.workflowUsecase.CreateWorkflowRecord(ctx, app, oamApp, workflow); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// step4: check and create namespace
|
||||
@@ -657,19 +623,46 @@ func (c *applicationUsecaseImpl) Deploy(ctx context.Context, app *model.Applicat
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) renderOAMApplication(ctx context.Context, appModel *model.Application, reqWorkflowName, 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
|
||||
var err error
|
||||
if reqWorkflowName != "" {
|
||||
workflow, err = c.workflowUsecase.GetWorkflow(ctx, appModel, reqWorkflowName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
workflow, err = c.workflowUsecase.GetApplicationDefaultWorkflow(ctx, appModel)
|
||||
if err != nil && !errors.Is(err, bcode.ErrWorkflowNoDefault) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if workflow == nil || workflow.EnvName == "" {
|
||||
return nil, bcode.ErrWorkflowNotExist
|
||||
}
|
||||
|
||||
labels := make(map[string]string)
|
||||
for key, value := range appModel.Labels {
|
||||
labels[key] = value
|
||||
}
|
||||
labels[oam.AnnotationAppName] = appModel.Name
|
||||
|
||||
var app = &v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: appModel.Name,
|
||||
Name: converAppName(appModel.Name, workflow.EnvName),
|
||||
Namespace: appModel.Namespace,
|
||||
Labels: appModel.Labels,
|
||||
Labels: labels,
|
||||
Annotations: map[string]string{
|
||||
oam.AnnotationDeployVersion: version,
|
||||
// publish version is the identifier of workflow record
|
||||
oam.AnnotationPublishVersion: utils.GenerateVersion(reqWorkflowName),
|
||||
oam.AnnotationAppName: appModel.Name,
|
||||
oam.AnnotationAppAlias: appModel.Alias,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -705,7 +698,7 @@ func (c *applicationUsecaseImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
traits = append(traits, aTrait)
|
||||
}
|
||||
bc := common.ApplicationComponent{
|
||||
Name: component.Name,
|
||||
Name: converComponentName(component.Name, workflow.EnvName),
|
||||
Type: component.Type,
|
||||
ExternalRevision: component.ExternalRevision,
|
||||
DependsOn: component.DependsOn,
|
||||
@@ -732,48 +725,29 @@ func (c *applicationUsecaseImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
}
|
||||
app.Spec.Policies = append(app.Spec.Policies, apolicy)
|
||||
}
|
||||
|
||||
// Priority 1 uses the requested workflow as release .
|
||||
// Priority 2 uses the default workflow as release .
|
||||
var workflow *model.Workflow
|
||||
if reqWorkflowName != "" {
|
||||
workflow, err = c.workflowUsecase.GetWorkflow(ctx, reqWorkflowName)
|
||||
if workflow.EnvName != "" {
|
||||
envPolicy, err := c.genPolicyByEnv(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if workflow.EnvName != "" {
|
||||
envPolicy, err := c.genPolicyByEnv(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app.Spec.Policies = append(app.Spec.Policies, envPolicy)
|
||||
}
|
||||
|
||||
} else {
|
||||
workflow, err = c.workflowUsecase.GetApplicationDefaultWorkflow(ctx, appModel)
|
||||
if err != nil && !errors.Is(err, bcode.ErrWorkflowNoDefault) {
|
||||
return nil, err
|
||||
}
|
||||
app.Spec.Policies = append(app.Spec.Policies, envPolicy)
|
||||
}
|
||||
|
||||
if workflow != nil {
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var wstep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
}
|
||||
if step.Properties != nil {
|
||||
wstep.Properties = step.Properties.RawExtension()
|
||||
}
|
||||
steps = append(steps, wstep)
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var wstep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
}
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
if step.Properties != nil {
|
||||
wstep.Properties = step.Properties.RawExtension()
|
||||
}
|
||||
steps = append(steps, wstep)
|
||||
}
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
}
|
||||
|
||||
return app, nil
|
||||
@@ -796,7 +770,13 @@ func (c *applicationUsecaseImpl) converAppModelToBase(app *model.Application) *a
|
||||
// DeleteApplication delete application
|
||||
func (c *applicationUsecaseImpl) DeleteApplication(ctx context.Context, app *model.Application) error {
|
||||
// TODO: check app can be deleted
|
||||
|
||||
crs, err := c.GetApplicationCR(ctx, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(crs.Items) > 0 {
|
||||
return bcode.ErrApplicationRefusedDelete
|
||||
}
|
||||
// query all components to deleted
|
||||
components, err := c.ListComponents(ctx, app, apisv1.ListApplicationComponentOptions{})
|
||||
if err != nil {
|
||||
@@ -809,7 +789,7 @@ func (c *applicationUsecaseImpl) DeleteApplication(ctx context.Context, app *mod
|
||||
}
|
||||
|
||||
// delete workflow
|
||||
if err := c.workflowUsecase.DeleteWorkflow(ctx, app.Name); err != nil && !errors.Is(err, bcode.ErrWorkflowNotExist) {
|
||||
if err := c.workflowUsecase.DeleteWorkflowByApp(ctx, app); err != nil && !errors.Is(err, bcode.ErrWorkflowNotExist) {
|
||||
log.Logger.Errorf("delete workflow %s failure %s", app.Name, err.Error())
|
||||
}
|
||||
|
||||
@@ -834,6 +814,50 @@ func (c *applicationUsecaseImpl) DeleteApplication(ctx context.Context, app *mod
|
||||
return c.ds.Delete(ctx, app)
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) GetApplicationComponent(ctx context.Context, app *model.Application, componentName string) (*model.ApplicationComponent, error) {
|
||||
var component = model.ApplicationComponent{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
Name: componentName,
|
||||
}
|
||||
err := c.ds.Get(ctx, &component)
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil, bcode.ErrApplicationComponetNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &component, nil
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) UpdateComponent(ctx context.Context, app *model.Application, component *model.ApplicationComponent, req apisv1.UpdateApplicationComponentRequest) (*apisv1.ComponentBase, error) {
|
||||
if req.Alias != nil {
|
||||
component.Alias = *req.Alias
|
||||
}
|
||||
if req.Description != nil {
|
||||
component.Description = *req.Description
|
||||
}
|
||||
if req.DependsOn != nil {
|
||||
component.DependsOn = *req.DependsOn
|
||||
}
|
||||
if req.Icon != nil {
|
||||
component.Icon = *req.Icon
|
||||
}
|
||||
if req.Labels != nil {
|
||||
component.Labels = *req.Labels
|
||||
}
|
||||
if req.Properties != nil {
|
||||
properties, err := model.NewJSONStructByString(*req.Properties)
|
||||
if err != nil {
|
||||
return nil, bcode.ErrInvalidProperties
|
||||
}
|
||||
component.Properties = properties
|
||||
}
|
||||
if err := c.ds.Put(ctx, component); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return converComponentModelToBase(component), nil
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) AddComponent(ctx context.Context, app *model.Application, com apisv1.CreateComponentRequest) (*apisv1.ComponentBase, error) {
|
||||
componentModel := model.ApplicationComponent{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
@@ -859,6 +883,13 @@ func (c *applicationUsecaseImpl) AddComponent(ctx context.Context, app *model.Ap
|
||||
log.Logger.Warnf("add component for app %s failure %s", app.PrimaryKey(), err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return converComponentModelToBase(&componentModel), nil
|
||||
}
|
||||
|
||||
func converComponentModelToBase(componentModel *model.ApplicationComponent) *apisv1.ComponentBase {
|
||||
if componentModel == nil {
|
||||
return nil
|
||||
}
|
||||
return &apisv1.ComponentBase{
|
||||
Name: componentModel.Name,
|
||||
Description: componentModel.Description,
|
||||
@@ -869,7 +900,7 @@ func (c *applicationUsecaseImpl) AddComponent(ctx context.Context, app *model.Ap
|
||||
Creator: componentModel.Creator,
|
||||
CreateTime: componentModel.CreateTime,
|
||||
UpdateTime: componentModel.UpdateTime,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) DeleteComponent(ctx context.Context, app *model.Application, componentName string) error {
|
||||
@@ -1096,6 +1127,29 @@ func (c *applicationUsecaseImpl) DetailRevision(ctx context.Context, appName, re
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *applicationUsecaseImpl) Statistics(ctx context.Context, app *model.Application) (*apisv1.ApplicationStatisticsResponse, error) {
|
||||
var targetMap = make(map[string]int)
|
||||
envbinding, err := c.envBindingUsecase.GetEnvBindings(ctx, app)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("query app envbinding failure %s", err.Error())
|
||||
}
|
||||
for _, env := range envbinding {
|
||||
for _, target := range env.TargetNames {
|
||||
targetMap[target]++
|
||||
}
|
||||
}
|
||||
count, err := c.ds.Count(ctx, &model.ApplicationRevision{AppPrimaryKey: app.PrimaryKey()}, &datastore.FilterOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &apisv1.ApplicationStatisticsResponse{
|
||||
EnvCount: int64(len(envbinding)),
|
||||
DeliveryTargetCount: int64(len(targetMap)),
|
||||
RevisonCount: count,
|
||||
WorkflowCount: c.workflowUsecase.CountWorkflow(ctx, app),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createTargetClusterEnv(envBind apisv1.EnvBindingBase, target *model.DeliveryTarget) v1alpha1.EnvConfig {
|
||||
placement := v1alpha1.EnvPlacement{}
|
||||
var componentSelector *v1alpha1.EnvSelector
|
||||
@@ -1115,18 +1169,18 @@ func createTargetClusterEnv(envBind apisv1.EnvBindingBase, target *model.Deliver
|
||||
}
|
||||
}
|
||||
|
||||
func converAppName(app *model.Application, envName string) string {
|
||||
return fmt.Sprintf("%s-%s", app.Name, envName)
|
||||
func converAppName(appModelName, envName string) string {
|
||||
return fmt.Sprintf("%s-%s", appModelName, envName)
|
||||
}
|
||||
|
||||
func converComponentName(componentModelName, envName string) string {
|
||||
return fmt.Sprintf("%s-%s", componentModelName, envName)
|
||||
}
|
||||
|
||||
func genPolicyName(envName string) string {
|
||||
return fmt.Sprintf("%s-%s", EnvBindingPolicyDefaultName, envName)
|
||||
}
|
||||
|
||||
func genWorkflowName(app *model.Application, envName string) string {
|
||||
return fmt.Sprintf("%s-%s", app.Name, envName)
|
||||
}
|
||||
|
||||
func genPolicyEnvName(targetName string) string {
|
||||
return targetName
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
@@ -158,9 +157,8 @@ var _ = Describe("Test application usecase function", func() {
|
||||
})
|
||||
|
||||
It("Test ListApplications function", func() {
|
||||
apps, err := appUsecase.ListApplications(context.TODO(), v1.ListApplicatioOptions{})
|
||||
_, err := appUsecase.ListApplications(context.TODO(), v1.ListApplicatioOptions{})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(len(apps), 3)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test DetailApplication function", func() {
|
||||
@@ -170,29 +168,8 @@ var _ = Describe("Test application usecase function", func() {
|
||||
|
||||
detail, err := appUsecase.DetailApplication(context.TODO(), appModel)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(detail.ResourceInfo.ComponentNum, 2)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(len(detail.Policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test GetWorkflow function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
|
||||
_, err = workflowUsecase.GetWorkflow(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test ListPolicies function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
|
||||
policies, err := appUsecase.ListPolicies(context.TODO(), appModel)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(len(policies), 1)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(policies[0].Type, "env-binding")).Should(BeEmpty())
|
||||
Expect((*policies[0].Properties)["envs"]).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(detail.ResourceInfo.ComponentNum, int64(2))).Should(BeEmpty())
|
||||
Expect(cmp.Diff(len(detail.Policies), 0)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test ListComponents function", func() {
|
||||
@@ -233,17 +210,6 @@ var _ = Describe("Test application usecase function", func() {
|
||||
Expect(cmp.Diff(strings.Contains((*detail.Properties)["image"].(string), "crccheck/hello-world"), true)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test DetailPolicy function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
|
||||
detail, err := appUsecase.DetailPolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(detail.Type, "env-binding")).Should(BeEmpty())
|
||||
Expect((*detail.Properties)["envs"]).ShouldNot(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test AddComponent function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -279,23 +245,34 @@ var _ = Describe("Test application usecase function", func() {
|
||||
Name: EnvBindingPolicyDefaultName,
|
||||
Description: "this is a test2 policy",
|
||||
Type: "env-binding",
|
||||
Properties: ``,
|
||||
})
|
||||
Expect(cmp.Equal(err, bcode.ErrApplicationPolicyExist, cmpopts.EquateErrors())).Should(BeTrue())
|
||||
_, err = appUsecase.AddPolicy(context.TODO(), appModel, v1.CreatePolicyRequest{
|
||||
Name: "env-binding-2",
|
||||
Description: "this is a test2 policy",
|
||||
Type: "env-binding",
|
||||
Properties: `{"envs":{ "name": "test", "placement":{"namespaceSelector":{ "name": "TEST_NAMESPACE"}}, "selector":{ "components": ["data-worker"]}}}`,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = appUsecase.AddPolicy(context.TODO(), appModel, v1.CreatePolicyRequest{
|
||||
Name: EnvBindingPolicyDefaultName,
|
||||
Description: "this is a test2 policy",
|
||||
Type: "env-binding",
|
||||
Properties: ``,
|
||||
})
|
||||
Expect(cmp.Equal(err, bcode.ErrApplicationPolicyExist, cmpopts.EquateErrors())).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test ListPolicies function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
|
||||
policies, err := appUsecase.ListPolicies(context.TODO(), appModel)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(len(policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test DetailPolicy function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
detail, err := appUsecase.DetailPolicy(context.TODO(), appModel, "env-binding-2")
|
||||
detail, err := appUsecase.DetailPolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(detail.Properties).ShouldNot(BeNil())
|
||||
Expect((*detail.Properties)["envs"]).ShouldNot(BeEmpty())
|
||||
@@ -305,7 +282,7 @@ var _ = Describe("Test application usecase function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
base, err := appUsecase.UpdatePolicy(context.TODO(), appModel, "env-binding-2", v1.UpdatePolicyRequest{
|
||||
base, err := appUsecase.UpdatePolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName, v1.UpdatePolicyRequest{
|
||||
Type: "env-binding",
|
||||
Properties: `{"envs":{}}`,
|
||||
})
|
||||
@@ -317,7 +294,7 @@ var _ = Describe("Test application usecase function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
err = appUsecase.DeletePolicy(context.TODO(), appModel, "env-binding-2")
|
||||
err = appUsecase.DeletePolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName)
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
@@ -402,24 +379,6 @@ var _ = Describe("Test application usecase function", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test Deploy Application function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
|
||||
res, err := appUsecase.Deploy(context.TODO(), appModel, v1.ApplicationDeployRequest{
|
||||
Note: "unit test deploy",
|
||||
TriggerType: "api",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(res.Status, model.RevisionStatusRunning)).Should(BeEmpty())
|
||||
|
||||
var oam v1beta1.Application
|
||||
err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: appModel.Name, Namespace: appModel.Namespace}, &oam)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(len(oam.Spec.Components), 2)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(len(oam.Spec.Policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test DeleteApplication function", func() {
|
||||
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd")
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -478,15 +437,16 @@ var _ = Describe("Test application usecase function", func() {
|
||||
})
|
||||
})
|
||||
|
||||
func createTestSuspendApp(ctx context.Context, appName, revisionVersion, wfName, recordName string, kubeClient client.Client) (*v1beta1.Application, error) {
|
||||
func createTestSuspendApp(ctx context.Context, appName, envName, revisionVersion, wfName, recordName string, kubeClient client.Client) (*v1beta1.Application, error) {
|
||||
testapp := &v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: appName,
|
||||
Name: converAppName(appName, envName),
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
oam.AnnotationDeployVersion: revisionVersion,
|
||||
oam.AnnotationWorkflowName: wfName,
|
||||
oam.AnnotationPublishVersion: recordName,
|
||||
oam.AnnotationAppName: appName,
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
|
||||
@@ -154,6 +154,8 @@ func convertCreateReqToDeliveryTargetModel(req apisv1.CreateDeliveryTargetReques
|
||||
}
|
||||
|
||||
func convertFromDeliveryTargetModel(deliveryTarget *model.DeliveryTarget) *apisv1.DeliveryTargetBase {
|
||||
var appNum int64 = 0
|
||||
// TODO: query app num in target
|
||||
return &apisv1.DeliveryTargetBase{
|
||||
Name: deliveryTarget.Name,
|
||||
Namespace: deliveryTarget.Namespace,
|
||||
@@ -163,5 +165,6 @@ func convertFromDeliveryTargetModel(deliveryTarget *model.DeliveryTarget) *apisv
|
||||
Variable: deliveryTarget.Variable,
|
||||
CreateTime: deliveryTarget.CreateTime,
|
||||
UpdateTime: deliveryTarget.UpdateTime,
|
||||
AppNum: appNum,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,21 @@ package usecase
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
)
|
||||
|
||||
// EnvBindingUsecase envbinding usecase
|
||||
@@ -41,19 +46,26 @@ type EnvBindingUsecase interface {
|
||||
UpdateEnvBinding(ctx context.Context, app *model.Application, envName string, diff apisv1.PutApplicationEnvRequest) (*apisv1.DetailEnvBindingResponse, error)
|
||||
DeleteEnvBinding(ctx context.Context, app *model.Application, envName string) error
|
||||
BatchDeleteEnvBinding(ctx context.Context, app *model.Application) error
|
||||
DetailEnvBinding(ctx context.Context, envBinding *model.EnvBinding) (*apisv1.DetailEnvBindingResponse, error)
|
||||
DetailEnvBinding(ctx context.Context, app *model.Application, envBinding *model.EnvBinding) (*apisv1.DetailEnvBindingResponse, error)
|
||||
ApplicationEnvRecycle(ctx context.Context, appModel *model.Application, envBinding *model.EnvBinding) error
|
||||
}
|
||||
|
||||
type envBindingUsecaseImpl struct {
|
||||
ds datastore.DataStore
|
||||
workflowUsecase WorkflowUsecase
|
||||
kubeClient client.Client
|
||||
}
|
||||
|
||||
// NewEnvBindingUsecase new envBinding usecase
|
||||
func NewEnvBindingUsecase(ds datastore.DataStore, workflowUsecase WorkflowUsecase) EnvBindingUsecase {
|
||||
kubecli, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
log.Logger.Fatalf("get kubeclient failure %s", err.Error())
|
||||
}
|
||||
return &envBindingUsecaseImpl{
|
||||
ds: ds,
|
||||
workflowUsecase: workflowUsecase,
|
||||
kubeClient: kubecli,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +77,17 @@ func (e *envBindingUsecaseImpl) GetEnvBindings(ctx context.Context, app *model.A
|
||||
if err != nil {
|
||||
return nil, bcode.ErrEnvBindingsNotExist
|
||||
}
|
||||
deliveryTarget := model.DeliveryTarget{
|
||||
Namespace: app.Namespace,
|
||||
}
|
||||
deliveryTargets, err := e.ds.List(ctx, &deliveryTarget, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var list []*apisv1.EnvBindingBase
|
||||
for _, ebd := range envBindings {
|
||||
eb := ebd.(*model.EnvBinding)
|
||||
list = append(list, convertEnvbindingModelToBase(eb))
|
||||
list = append(list, convertEnvbindingModelToBase(app, eb, deliveryTargets))
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
@@ -81,7 +100,7 @@ func (e *envBindingUsecaseImpl) GetEnvBinding(ctx context.Context, app *model.Ap
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return e.DetailEnvBinding(ctx, envBinding)
|
||||
return e.DetailEnvBinding(ctx, app, envBinding)
|
||||
}
|
||||
|
||||
func (e *envBindingUsecaseImpl) CheckAppEnvBindingsContainTarget(ctx context.Context, app *model.Application, targetName string) (bool, error) {
|
||||
@@ -165,18 +184,23 @@ func (e *envBindingUsecaseImpl) UpdateEnvBinding(ctx context.Context, app *model
|
||||
if err := e.ds.Put(ctx, envBindingModel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.DetailEnvBinding(ctx, envBindingModel)
|
||||
return e.DetailEnvBinding(ctx, app, envBindingModel)
|
||||
}
|
||||
|
||||
func (e *envBindingUsecaseImpl) DeleteEnvBinding(ctx context.Context, app *model.Application, envName string) error {
|
||||
envBinding, err := e.getBindingByEnv(ctx, app, envName)
|
||||
func (e *envBindingUsecaseImpl) DeleteEnvBinding(ctx context.Context, appModel *model.Application, envName string) error {
|
||||
envBinding, err := e.getBindingByEnv(ctx, appModel, envName)
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return bcode.ErrEnvBindingNotExist
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := e.ds.Delete(ctx, &model.EnvBinding{AppPrimaryKey: app.PrimaryKey(), Name: envBinding.Name}); err != nil {
|
||||
var app v1beta1.Application
|
||||
err = e.kubeClient.Get(ctx, types.NamespacedName{Namespace: app.Namespace, Name: converAppName(appModel.Name, envBinding.Name)}, &app)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return bcode.ErrApplicationRefusedDelete
|
||||
}
|
||||
if err := e.ds.Delete(ctx, &model.EnvBinding{AppPrimaryKey: appModel.PrimaryKey(), Name: envBinding.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -230,7 +254,8 @@ func (e *envBindingUsecaseImpl) createEnvWorkflow(ctx context.Context, app *mode
|
||||
}
|
||||
_, err := e.workflowUsecase.CreateWorkflow(ctx, app, apisv1.CreateWorkflowRequest{
|
||||
AppName: app.PrimaryKey(),
|
||||
Name: genWorkflowName(app, env.Name),
|
||||
Name: env.Name,
|
||||
Alias: fmt.Sprintf("%s env workflow", env.Alias),
|
||||
Description: "Created automatically by envbinding.",
|
||||
EnvName: env.Name,
|
||||
Steps: steps,
|
||||
@@ -242,12 +267,31 @@ func (e *envBindingUsecaseImpl) createEnvWorkflow(ctx context.Context, app *mode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *envBindingUsecaseImpl) DetailEnvBinding(ctx context.Context, envBinding *model.EnvBinding) (*apisv1.DetailEnvBindingResponse, error) {
|
||||
func (e *envBindingUsecaseImpl) DetailEnvBinding(ctx context.Context, app *model.Application, envBinding *model.EnvBinding) (*apisv1.DetailEnvBindingResponse, error) {
|
||||
deliveryTarget := model.DeliveryTarget{
|
||||
Namespace: app.Namespace,
|
||||
}
|
||||
deliveryTargets, err := e.ds.List(ctx, &deliveryTarget, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &apisv1.DetailEnvBindingResponse{
|
||||
EnvBindingBase: *convertEnvbindingModelToBase(envBinding),
|
||||
EnvBindingBase: *convertEnvbindingModelToBase(app, envBinding, deliveryTargets),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *envBindingUsecaseImpl) ApplicationEnvRecycle(ctx context.Context, appModel *model.Application, envBinding *model.EnvBinding) error {
|
||||
var app v1beta1.Application
|
||||
err := e.kubeClient.Get(ctx, types.NamespacedName{Namespace: app.Namespace, Name: converAppName(appModel.Name, envBinding.Name)}, &app)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return e.kubeClient.Delete(ctx, &app)
|
||||
}
|
||||
|
||||
func convertCreateReqToEnvBindingModel(app *model.Application, req apisv1.CreateApplicationEnvRequest) model.EnvBinding {
|
||||
envBinding := model.EnvBinding{
|
||||
AppPrimaryKey: app.Name,
|
||||
@@ -259,15 +303,29 @@ func convertCreateReqToEnvBindingModel(app *model.Application, req apisv1.Create
|
||||
return envBinding
|
||||
}
|
||||
|
||||
func convertEnvbindingModelToBase(envBinding *model.EnvBinding) *apisv1.EnvBindingBase {
|
||||
func convertEnvbindingModelToBase(app *model.Application, envBinding *model.EnvBinding, deliveryTargets []datastore.Entity) *apisv1.EnvBindingBase {
|
||||
var dtMap = make(map[string]*model.DeliveryTarget, len(deliveryTargets))
|
||||
for _, dte := range deliveryTargets {
|
||||
dt := dte.(*model.DeliveryTarget)
|
||||
dtMap[dt.Name] = dt
|
||||
}
|
||||
var targets []apisv1.DeliveryTargetBase
|
||||
for _, targetName := range envBinding.TargetNames {
|
||||
dt := dtMap[targetName]
|
||||
if dt != nil {
|
||||
targets = append(targets, *convertFromDeliveryTargetModel(dt))
|
||||
}
|
||||
}
|
||||
ebb := &apisv1.EnvBindingBase{
|
||||
Name: envBinding.Name,
|
||||
Alias: envBinding.Alias,
|
||||
Description: envBinding.Description,
|
||||
TargetNames: envBinding.TargetNames,
|
||||
Targets: targets,
|
||||
ComponentSelector: (*apisv1.ComponentSelector)(envBinding.ComponentSelector),
|
||||
CreateTime: envBinding.CreateTime,
|
||||
UpdateTime: envBinding.UpdateTime,
|
||||
AppDeployName: converAppName(app.Name, envBinding.Name),
|
||||
}
|
||||
return ebb
|
||||
}
|
||||
|
||||
+92
-92
@@ -99,20 +99,6 @@
|
||||
label: 持久化存储
|
||||
sort: 11
|
||||
subParameters:
|
||||
- description: ""
|
||||
jsonKey: mountPath
|
||||
label: MountPath
|
||||
sort: 100
|
||||
uiType: Input
|
||||
validate:
|
||||
required: true
|
||||
- description: ""
|
||||
jsonKey: name
|
||||
label: Name
|
||||
sort: 100
|
||||
uiType: Input
|
||||
validate:
|
||||
required: true
|
||||
- description: 'Specify volume type, options: "pvc","configMap","secret","emptyDir"'
|
||||
jsonKey: type
|
||||
label: Type
|
||||
@@ -129,6 +115,20 @@
|
||||
- label: EmptyDir
|
||||
value: emptyDir
|
||||
required: true
|
||||
- description: ""
|
||||
jsonKey: mountPath
|
||||
label: MountPath
|
||||
sort: 100
|
||||
uiType: Input
|
||||
validate:
|
||||
required: true
|
||||
- description: ""
|
||||
jsonKey: name
|
||||
label: Name
|
||||
sort: 100
|
||||
uiType: Input
|
||||
validate:
|
||||
required: true
|
||||
uiType: Structs
|
||||
validate: {}
|
||||
- description: Instructions for assessing whether the container is in a suitable state
|
||||
@@ -137,6 +137,24 @@
|
||||
label: ReadinessProbe检测
|
||||
sort: 13
|
||||
subParameters:
|
||||
- description: Instructions for assessing container health by probing a TCP socket.
|
||||
Either this attribute or the exec attribute or the httpGet attribute MUST be
|
||||
specified. This attribute is mutually exclusive with both the exec attribute
|
||||
and the httpGet attribute.
|
||||
jsonKey: tcpSocket
|
||||
label: TcpSocket
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: The TCP socket within the container that should be probed to assess
|
||||
container health.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
- description: Number of seconds after which the probe times out.
|
||||
jsonKey: timeoutSeconds
|
||||
label: TimeoutSeconds
|
||||
@@ -182,6 +200,14 @@
|
||||
label: HttpGet
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: The TCP socket within the container to which the HTTP GET request
|
||||
should be directed.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
- description: ""
|
||||
jsonKey: httpHeaders
|
||||
label: HttpHeaders
|
||||
@@ -211,14 +237,6 @@
|
||||
uiType: Input
|
||||
validate:
|
||||
required: true
|
||||
- description: The TCP socket within the container to which the HTTP GET request
|
||||
should be directed.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
- description: Number of seconds after the container is started before the first
|
||||
@@ -247,24 +265,6 @@
|
||||
validate:
|
||||
defaultValue: 1
|
||||
required: true
|
||||
- description: Instructions for assessing container health by probing a TCP socket.
|
||||
Either this attribute or the exec attribute or the httpGet attribute MUST be
|
||||
specified. This attribute is mutually exclusive with both the exec attribute
|
||||
and the httpGet attribute.
|
||||
jsonKey: tcpSocket
|
||||
label: TcpSocket
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: The TCP socket within the container that should be probed to assess
|
||||
container health.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
uiType: Group
|
||||
validate: {}
|
||||
- description: Instructions for assessing whether the container is alive.
|
||||
@@ -272,6 +272,52 @@
|
||||
label: LivenessProbe检测
|
||||
sort: 15
|
||||
subParameters:
|
||||
- description: Instructions for assessing container health by probing a TCP socket.
|
||||
Either this attribute or the exec attribute or the httpGet attribute MUST be
|
||||
specified. This attribute is mutually exclusive with both the exec attribute
|
||||
and the httpGet attribute.
|
||||
jsonKey: tcpSocket
|
||||
label: TcpSocket
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: The TCP socket within the container that should be probed to assess
|
||||
container health.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
- description: Number of seconds after which the probe times out.
|
||||
jsonKey: timeoutSeconds
|
||||
label: TimeoutSeconds
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
defaultValue: 1
|
||||
required: true
|
||||
- description: Instructions for assessing container health by executing a command.
|
||||
Either this attribute or the httpGet attribute or the tcpSocket attribute MUST
|
||||
be specified. This attribute is mutually exclusive with both the httpGet attribute
|
||||
and the tcpSocket attribute.
|
||||
jsonKey: exec
|
||||
label: Exec
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: A command to be executed inside the container to assess its health.
|
||||
Each space delimited token of the command is a separate array element. Commands
|
||||
exiting 0 are considered to be successful probes, whilst all other exit codes
|
||||
are considered failures.
|
||||
jsonKey: command
|
||||
label: Command
|
||||
sort: 100
|
||||
uiType: Strings
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
- description: Number of consecutive failures required to determine the container
|
||||
is not alive (liveness probe) or not ready (readiness probe).
|
||||
jsonKey: failureThreshold
|
||||
@@ -354,52 +400,6 @@
|
||||
validate:
|
||||
defaultValue: 1
|
||||
required: true
|
||||
- description: Instructions for assessing container health by probing a TCP socket.
|
||||
Either this attribute or the exec attribute or the httpGet attribute MUST be
|
||||
specified. This attribute is mutually exclusive with both the exec attribute
|
||||
and the httpGet attribute.
|
||||
jsonKey: tcpSocket
|
||||
label: TcpSocket
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: The TCP socket within the container that should be probed to assess
|
||||
container health.
|
||||
jsonKey: port
|
||||
label: Port
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
- description: Number of seconds after which the probe times out.
|
||||
jsonKey: timeoutSeconds
|
||||
label: TimeoutSeconds
|
||||
sort: 100
|
||||
uiType: Number
|
||||
validate:
|
||||
defaultValue: 1
|
||||
required: true
|
||||
- description: Instructions for assessing container health by executing a command.
|
||||
Either this attribute or the httpGet attribute or the tcpSocket attribute MUST
|
||||
be specified. This attribute is mutually exclusive with both the httpGet attribute
|
||||
and the tcpSocket attribute.
|
||||
jsonKey: exec
|
||||
label: Exec
|
||||
sort: 100
|
||||
subParameters:
|
||||
- description: A command to be executed inside the container to assess its health.
|
||||
Each space delimited token of the command is a separate array element. Commands
|
||||
exiting 0 are considered to be successful probes, whilst all other exit codes
|
||||
are considered failures.
|
||||
jsonKey: command
|
||||
label: Command
|
||||
sort: 100
|
||||
uiType: Strings
|
||||
validate:
|
||||
required: true
|
||||
uiType: KV
|
||||
validate: {}
|
||||
uiType: Group
|
||||
validate: {}
|
||||
- description: Specify image pull policy for your service
|
||||
@@ -416,6 +416,12 @@
|
||||
value: Always
|
||||
- label: 永不更新
|
||||
value: Never
|
||||
- description: Specify image pull secrets for your service
|
||||
jsonKey: imagePullSecrets
|
||||
label: ImagePullSecrets
|
||||
sort: 100
|
||||
uiType: Strings
|
||||
validate: {}
|
||||
- description: If addRevisionLabel is true, the appRevision label will be added to
|
||||
the underlying pods
|
||||
jsonKey: addRevisionLabel
|
||||
@@ -425,9 +431,3 @@
|
||||
validate:
|
||||
defaultValue: false
|
||||
required: true
|
||||
- description: Specify image pull secrets for your service
|
||||
jsonKey: imagePullSecrets
|
||||
label: ImagePullSecrets
|
||||
sort: 100
|
||||
uiType: Strings
|
||||
validate: {}
|
||||
|
||||
@@ -48,20 +48,22 @@ const (
|
||||
|
||||
// WorkflowUsecase workflow manage api
|
||||
type WorkflowUsecase interface {
|
||||
ListApplicationWorkflow(ctx context.Context, app *model.Application, enable *bool) ([]*apisv1.WorkflowBase, error)
|
||||
GetWorkflow(ctx context.Context, workflowName string) (*model.Workflow, error)
|
||||
ListApplicationWorkflow(ctx context.Context, app *model.Application) ([]*apisv1.WorkflowBase, error)
|
||||
GetWorkflow(ctx context.Context, app *model.Application, workflowName string) (*model.Workflow, error)
|
||||
DetailWorkflow(ctx context.Context, workflow *model.Workflow) (*apisv1.DetailWorkflowResponse, error)
|
||||
GetApplicationDefaultWorkflow(ctx context.Context, app *model.Application) (*model.Workflow, error)
|
||||
DeleteWorkflow(ctx context.Context, workflowName string) error
|
||||
DeleteWorkflow(ctx context.Context, app *model.Application, workflowName string) error
|
||||
DeleteWorkflowByApp(ctx context.Context, app *model.Application) error
|
||||
CreateWorkflow(ctx context.Context, app *model.Application, req apisv1.CreateWorkflowRequest) (*apisv1.DetailWorkflowResponse, error)
|
||||
CreateWorkflowRecord(ctx context.Context, app *v1beta1.Application) error
|
||||
UpdateWorkflow(ctx context.Context, workflow *model.Workflow, req apisv1.UpdateWorkflowRequest) (*apisv1.DetailWorkflowResponse, error)
|
||||
ListWorkflowRecords(ctx context.Context, workflowName string, page, pageSize int) (*apisv1.ListWorkflowRecordsResponse, error)
|
||||
DetailWorkflowRecord(ctx context.Context, workflowName, recordName string) (*apisv1.DetailWorkflowRecordResponse, error)
|
||||
CreateWorkflowRecord(ctx context.Context, appModel *model.Application, app *v1beta1.Application, workflow *model.Workflow) error
|
||||
ListWorkflowRecords(ctx context.Context, workflow *model.Workflow, page, pageSize int) (*apisv1.ListWorkflowRecordsResponse, error)
|
||||
DetailWorkflowRecord(ctx context.Context, workflow *model.Workflow, recordName string) (*apisv1.DetailWorkflowRecordResponse, error)
|
||||
SyncWorkflowRecord(ctx context.Context) error
|
||||
ResumeRecord(ctx context.Context, appModel *model.Application, recordName string) error
|
||||
TerminateRecord(ctx context.Context, appModel *model.Application, recordName string) error
|
||||
RollbackRecord(ctx context.Context, appModel *model.Application, recordName, revisionName string) error
|
||||
ResumeRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName string) error
|
||||
TerminateRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName string) error
|
||||
RollbackRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName, revisionName string) error
|
||||
CountWorkflow(ctx context.Context, app *model.Application) int64
|
||||
}
|
||||
|
||||
// NewWorkflowUsecase new workflow usecase
|
||||
@@ -84,9 +86,10 @@ type workflowUsecaseImpl struct {
|
||||
}
|
||||
|
||||
// DeleteWorkflow delete application workflow
|
||||
func (w *workflowUsecaseImpl) DeleteWorkflow(ctx context.Context, workflowName string) error {
|
||||
func (w *workflowUsecaseImpl) DeleteWorkflow(ctx context.Context, app *model.Application, workflowName string) error {
|
||||
var workflow = &model.Workflow{
|
||||
Name: workflowName,
|
||||
Name: workflowName,
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
if err := w.ds.Delete(ctx, workflow); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
@@ -97,7 +100,30 @@ func (w *workflowUsecaseImpl) DeleteWorkflow(ctx context.Context, workflowName s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) DeleteWorkflowByApp(ctx context.Context, app *model.Application) error {
|
||||
var workflow = &model.Workflow{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
|
||||
workflows, err := w.ds.List(ctx, workflow, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for i := range workflows {
|
||||
if err := w.ds.Delete(ctx, workflows[i]); err != nil {
|
||||
log.Logger.Errorf("delete workflow %s failure %s", workflows[i].PrimaryKey(), err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) CreateWorkflow(ctx context.Context, app *model.Application, req apisv1.CreateWorkflowRequest) (*apisv1.DetailWorkflowResponse, error) {
|
||||
if req.EnvName == "" {
|
||||
return nil, bcode.ErrWorkflowNoEnv
|
||||
}
|
||||
var steps []model.WorkflowStep
|
||||
for _, step := range req.Steps {
|
||||
properties, err := model.NewJSONStructByString(step.Properties)
|
||||
@@ -106,11 +132,13 @@ func (w *workflowUsecaseImpl) CreateWorkflow(ctx context.Context, app *model.App
|
||||
return nil, bcode.ErrInvalidProperties
|
||||
}
|
||||
steps = append(steps, model.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
Properties: properties,
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
Description: step.Description,
|
||||
DependsOn: step.DependsOn,
|
||||
Properties: properties,
|
||||
})
|
||||
}
|
||||
// It is allowed to set multiple workflows as default, and only one takes effect.
|
||||
@@ -155,39 +183,46 @@ func (w *workflowUsecaseImpl) UpdateWorkflow(ctx context.Context, workflow *mode
|
||||
return w.DetailWorkflow(ctx, workflow)
|
||||
}
|
||||
|
||||
// DetailWorkflow detail workflow
|
||||
func (w *workflowUsecaseImpl) DetailWorkflow(ctx context.Context, workflow *model.Workflow) (*apisv1.DetailWorkflowResponse, error) {
|
||||
func converWorkflowBase(workflow *model.Workflow) apisv1.WorkflowBase {
|
||||
var steps []apisv1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
apiStep := apisv1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
Properties: step.Properties.JSON(),
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Description: step.Description,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
Properties: step.Properties.JSON(),
|
||||
DependsOn: step.DependsOn,
|
||||
}
|
||||
if step.Properties != nil {
|
||||
apiStep.Properties = step.Properties.JSON()
|
||||
}
|
||||
steps = append(steps, apiStep)
|
||||
}
|
||||
return apisv1.WorkflowBase{
|
||||
Name: workflow.Name,
|
||||
Description: workflow.Description,
|
||||
Default: workflow.Default,
|
||||
EnvName: workflow.EnvName,
|
||||
CreateTime: workflow.CreateTime,
|
||||
UpdateTime: workflow.UpdateTime,
|
||||
Steps: steps,
|
||||
}
|
||||
}
|
||||
|
||||
// DetailWorkflow detail workflow
|
||||
func (w *workflowUsecaseImpl) DetailWorkflow(ctx context.Context, workflow *model.Workflow) (*apisv1.DetailWorkflowResponse, error) {
|
||||
return &apisv1.DetailWorkflowResponse{
|
||||
WorkflowBase: apisv1.WorkflowBase{
|
||||
Name: workflow.Name,
|
||||
Description: workflow.Description,
|
||||
Default: workflow.Default,
|
||||
EnvName: workflow.EnvName,
|
||||
CreateTime: workflow.CreateTime,
|
||||
UpdateTime: workflow.UpdateTime,
|
||||
},
|
||||
Steps: steps,
|
||||
WorkflowBase: converWorkflowBase(workflow),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetWorkflow get workflow model
|
||||
func (w *workflowUsecaseImpl) GetWorkflow(ctx context.Context, workflowName string) (*model.Workflow, error) {
|
||||
func (w *workflowUsecaseImpl) GetWorkflow(ctx context.Context, app *model.Application, workflowName string) (*model.Workflow, error) {
|
||||
var workflow = model.Workflow{
|
||||
Name: workflowName,
|
||||
Name: workflowName,
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
if err := w.ds.Get(ctx, &workflow); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
@@ -199,7 +234,7 @@ func (w *workflowUsecaseImpl) GetWorkflow(ctx context.Context, workflowName stri
|
||||
}
|
||||
|
||||
// ListApplicationWorkflow list application workflows
|
||||
func (w *workflowUsecaseImpl) ListApplicationWorkflow(ctx context.Context, app *model.Application, enable *bool) ([]*apisv1.WorkflowBase, error) {
|
||||
func (w *workflowUsecaseImpl) ListApplicationWorkflow(ctx context.Context, app *model.Application) ([]*apisv1.WorkflowBase, error) {
|
||||
var workflow = model.Workflow{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
@@ -210,14 +245,8 @@ func (w *workflowUsecaseImpl) ListApplicationWorkflow(ctx context.Context, app *
|
||||
var list []*apisv1.WorkflowBase
|
||||
for _, workflow := range workflows {
|
||||
wm := workflow.(*model.Workflow)
|
||||
list = append(list, &apisv1.WorkflowBase{
|
||||
Name: wm.Name,
|
||||
Description: wm.Description,
|
||||
Default: wm.Default,
|
||||
EnvName: wm.EnvName,
|
||||
CreateTime: wm.CreateTime,
|
||||
UpdateTime: wm.UpdateTime,
|
||||
})
|
||||
base := converWorkflowBase(wm)
|
||||
list = append(list, &base)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
@@ -239,9 +268,10 @@ func (w *workflowUsecaseImpl) GetApplicationDefaultWorkflow(ctx context.Context,
|
||||
}
|
||||
|
||||
// ListWorkflowRecords list workflow record
|
||||
func (w *workflowUsecaseImpl) ListWorkflowRecords(ctx context.Context, workflowName string, page, pageSize int) (*apisv1.ListWorkflowRecordsResponse, error) {
|
||||
func (w *workflowUsecaseImpl) ListWorkflowRecords(ctx context.Context, workflow *model.Workflow, page, pageSize int) (*apisv1.ListWorkflowRecordsResponse, error) {
|
||||
var record = model.WorkflowRecord{
|
||||
WorkflowPrimaryKey: workflowName,
|
||||
AppPrimaryKey: workflow.AppPrimaryKey,
|
||||
WorkflowName: workflow.Name,
|
||||
}
|
||||
records, err := w.ds.List(ctx, &record, &datastore.ListOptions{Page: page, PageSize: pageSize})
|
||||
if err != nil {
|
||||
@@ -267,13 +297,17 @@ func (w *workflowUsecaseImpl) ListWorkflowRecords(ctx context.Context, workflowN
|
||||
}
|
||||
|
||||
// DetailWorkflowRecord get workflow record detail with name
|
||||
func (w *workflowUsecaseImpl) DetailWorkflowRecord(ctx context.Context, workflowName, recordName string) (*apisv1.DetailWorkflowRecordResponse, error) {
|
||||
func (w *workflowUsecaseImpl) DetailWorkflowRecord(ctx context.Context, workflow *model.Workflow, recordName string) (*apisv1.DetailWorkflowRecordResponse, error) {
|
||||
var record = model.WorkflowRecord{
|
||||
WorkflowPrimaryKey: workflowName,
|
||||
Name: recordName,
|
||||
AppPrimaryKey: workflow.AppPrimaryKey,
|
||||
WorkflowName: workflow.Name,
|
||||
Name: recordName,
|
||||
}
|
||||
err := w.ds.Get(ctx, &record)
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil, bcode.ErrWorkflowRecordNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -283,6 +317,9 @@ func (w *workflowUsecaseImpl) DetailWorkflowRecord(ctx context.Context, workflow
|
||||
}
|
||||
err = w.ds.Get(ctx, &revision)
|
||||
if err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return nil, bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -307,23 +344,27 @@ func (w *workflowUsecaseImpl) SyncWorkflowRecord(ctx context.Context) error {
|
||||
|
||||
for _, item := range records {
|
||||
app := &v1beta1.Application{}
|
||||
index := item.Index()
|
||||
appPrimaryKey := index["appPrimaryKey"]
|
||||
namespace := index["namespace"]
|
||||
recordName := index["name"]
|
||||
|
||||
record := item.(*model.WorkflowRecord)
|
||||
workflow := &model.Workflow{
|
||||
Name: record.WorkflowName,
|
||||
AppPrimaryKey: record.AppPrimaryKey,
|
||||
}
|
||||
if err := w.ds.Get(ctx, workflow); err != nil {
|
||||
log.Logger.Errorf("get workflow %s/%s failure %s", record.AppPrimaryKey, record.WorkflowName, err.Error())
|
||||
continue
|
||||
}
|
||||
if err := w.kubeClient.Get(ctx, types.NamespacedName{
|
||||
Name: appPrimaryKey,
|
||||
Namespace: namespace,
|
||||
Name: converAppName(record.AppPrimaryKey, workflow.EnvName),
|
||||
Namespace: record.Namespace,
|
||||
}, app); err != nil {
|
||||
klog.ErrorS(err, "failed to get app", "app name", appPrimaryKey)
|
||||
klog.ErrorS(err, "failed to get app", "app name", record.AppPrimaryKey)
|
||||
return err
|
||||
}
|
||||
|
||||
// try to sync the status from the running application
|
||||
if app.Annotations != nil && app.Annotations[oam.AnnotationPublishVersion] == recordName {
|
||||
if err := w.syncWorkflowStatus(ctx, app, recordName); err != nil {
|
||||
klog.ErrorS(err, "failed to sync workflow status", "app name", appPrimaryKey, "workflow record name", recordName)
|
||||
if app.Annotations != nil && app.Annotations[oam.AnnotationPublishVersion] == record.Name {
|
||||
if err := w.syncWorkflowStatus(ctx, app, record.Name); err != nil {
|
||||
klog.ErrorS(err, "failed to sync workflow status", "app name", record.AppPrimaryKey, "workflow record name", record.Name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -331,19 +372,19 @@ func (w *workflowUsecaseImpl) SyncWorkflowRecord(ctx context.Context) error {
|
||||
// try to sync the status from the controller revision
|
||||
cr := &appsv1.ControllerRevision{}
|
||||
if err := w.kubeClient.Get(ctx, types.NamespacedName{
|
||||
Name: fmt.Sprintf("record-%s-%s", appPrimaryKey, recordName),
|
||||
Namespace: namespace,
|
||||
Name: fmt.Sprintf("record-%s-%s", record.AppPrimaryKey, record.Name),
|
||||
Namespace: record.Namespace,
|
||||
}, cr); err != nil {
|
||||
klog.ErrorS(err, "failed to get controller revision", "app name", appPrimaryKey, "workflow record name", recordName)
|
||||
klog.ErrorS(err, "failed to get controller revision", "app name", record.AppPrimaryKey, "workflow record name", record.Name)
|
||||
continue
|
||||
}
|
||||
appInRevision, err := util.RawExtension2Application(cr.Data)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to get app data in controller revision", "controller revision name", cr.Name, "app name", appPrimaryKey, "workflow record name", recordName)
|
||||
klog.ErrorS(err, "failed to get app data in controller revision", "controller revision name", cr.Name, "app name", record.AppPrimaryKey, "workflow record name", record.Name)
|
||||
continue
|
||||
}
|
||||
if err := w.syncWorkflowStatus(ctx, appInRevision, recordName); err != nil {
|
||||
klog.ErrorS(err, "failed to sync workflow status", "app name", appPrimaryKey, "workflow record version", recordName)
|
||||
if err := w.syncWorkflowStatus(ctx, appInRevision, record.Name); err != nil {
|
||||
klog.ErrorS(err, "failed to sync workflow status", "app name", record.AppPrimaryKey, "workflow record version", record.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -353,18 +394,26 @@ func (w *workflowUsecaseImpl) SyncWorkflowRecord(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) syncWorkflowStatus(ctx context.Context, app *v1beta1.Application, recordName string) error {
|
||||
|
||||
var record = &model.WorkflowRecord{
|
||||
AppPrimaryKey: app.Name,
|
||||
AppPrimaryKey: app.Annotations[oam.AnnotationAppName],
|
||||
Name: recordName,
|
||||
}
|
||||
if err := w.ds.Get(ctx, record); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return bcode.ErrWorkflowRecordNotExist
|
||||
}
|
||||
return err
|
||||
}
|
||||
var revision = &model.ApplicationRevision{
|
||||
AppPrimaryKey: app.Name,
|
||||
AppPrimaryKey: app.Annotations[oam.AnnotationAppName],
|
||||
Version: record.RevisionPrimaryKey,
|
||||
}
|
||||
|
||||
if err := w.ds.Get(ctx, revision); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -395,13 +444,10 @@ func (w *workflowUsecaseImpl) syncWorkflowStatus(ctx context.Context, app *v1bet
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) CreateWorkflowRecord(ctx context.Context, app *v1beta1.Application) error {
|
||||
func (w *workflowUsecaseImpl) CreateWorkflowRecord(ctx context.Context, appModel *model.Application, app *v1beta1.Application, workflow *model.Workflow) error {
|
||||
if app.Annotations == nil {
|
||||
return fmt.Errorf("empty annotations in application")
|
||||
}
|
||||
if app.Annotations[oam.AnnotationWorkflowName] == "" {
|
||||
return fmt.Errorf("failed to get workflow name from application")
|
||||
}
|
||||
if app.Annotations[oam.AnnotationPublishVersion] == "" {
|
||||
return fmt.Errorf("failed to get record version from application")
|
||||
}
|
||||
@@ -410,19 +456,26 @@ func (w *workflowUsecaseImpl) CreateWorkflowRecord(ctx context.Context, app *v1b
|
||||
}
|
||||
|
||||
return w.ds.Add(ctx, &model.WorkflowRecord{
|
||||
WorkflowPrimaryKey: app.Annotations[oam.AnnotationWorkflowName],
|
||||
AppPrimaryKey: app.Name,
|
||||
WorkflowName: workflow.Name,
|
||||
AppPrimaryKey: appModel.PrimaryKey(),
|
||||
RevisionPrimaryKey: app.Annotations[oam.AnnotationDeployVersion],
|
||||
Name: app.Annotations[oam.AnnotationPublishVersion],
|
||||
Namespace: app.Namespace,
|
||||
Namespace: appModel.Namespace,
|
||||
Finished: "false",
|
||||
StartTime: time.Now().Time,
|
||||
Status: model.RevisionStatusInit,
|
||||
})
|
||||
}
|
||||
func (w *workflowUsecaseImpl) CountWorkflow(ctx context.Context, app *model.Application) int64 {
|
||||
count, err := w.ds.Count(ctx, &model.Workflow{AppPrimaryKey: app.PrimaryKey()}, &datastore.FilterOptions{})
|
||||
if err != nil {
|
||||
log.Logger.Errorf("count app %s workflow failure %s", app.PrimaryKey(), err.Error())
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) ResumeRecord(ctx context.Context, appModel *model.Application, recordName string) error {
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel)
|
||||
func (w *workflowUsecaseImpl) ResumeRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName string) error {
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -438,8 +491,8 @@ func (w *workflowUsecaseImpl) ResumeRecord(ctx context.Context, appModel *model.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) TerminateRecord(ctx context.Context, appModel *model.Application, recordName string) error {
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel)
|
||||
func (w *workflowUsecaseImpl) TerminateRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName string) error {
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -455,7 +508,7 @@ func (w *workflowUsecaseImpl) TerminateRecord(ctx context.Context, appModel *mod
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) RollbackRecord(ctx context.Context, appModel *model.Application, recordName, revisionVersion string) error {
|
||||
func (w *workflowUsecaseImpl) RollbackRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName, revisionVersion string) error {
|
||||
if revisionVersion == "" {
|
||||
// find the latest complete revision version
|
||||
var revision = model.ApplicationRevision{
|
||||
@@ -472,23 +525,24 @@ func (w *workflowUsecaseImpl) RollbackRecord(ctx context.Context, appModel *mode
|
||||
return err
|
||||
}
|
||||
if len(revisions) == 0 {
|
||||
fmt.Errorf("there is no complete revision, please specify a revision version")
|
||||
return bcode.ErrApplicationNoReadyRevision
|
||||
}
|
||||
revisionVersion = revisions[0].Index()["version"]
|
||||
}
|
||||
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var record = &model.WorkflowRecord{
|
||||
AppPrimaryKey: appModel.Name,
|
||||
AppPrimaryKey: appModel.PrimaryKey(),
|
||||
Name: recordName,
|
||||
}
|
||||
if err := w.ds.Get(ctx, record); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oamApp, err := w.checkRecordRunning(ctx, appModel, workflow.EnvName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rollbackRevision = model.ApplicationRevision{
|
||||
AppPrimaryKey: appModel.Name,
|
||||
Version: revisionVersion,
|
||||
@@ -507,12 +561,11 @@ func (w *workflowUsecaseImpl) RollbackRecord(ctx context.Context, appModel *mode
|
||||
if oamApp.Annotations == nil {
|
||||
oamApp.Annotations = make(map[string]string)
|
||||
}
|
||||
newRecordName := utils.GenerateVersion(record.WorkflowPrimaryKey)
|
||||
newRecordName := utils.GenerateVersion(record.WorkflowName)
|
||||
oamApp.Annotations[oam.AnnotationDeployVersion] = revisionVersion
|
||||
oamApp.Annotations[oam.AnnotationPublishVersion] = newRecordName
|
||||
|
||||
// create a new workflow record
|
||||
if err := w.CreateWorkflowRecord(ctx, oamApp); err != nil {
|
||||
if err := w.CreateWorkflowRecord(ctx, appModel, oamApp, workflow); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -527,9 +580,9 @@ func (w *workflowUsecaseImpl) RollbackRecord(ctx context.Context, appModel *mode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowUsecaseImpl) checkRecordRunning(ctx context.Context, appModel *model.Application) (*v1beta1.Application, error) {
|
||||
func (w *workflowUsecaseImpl) checkRecordRunning(ctx context.Context, appModel *model.Application, envName string) (*v1beta1.Application, error) {
|
||||
oamApp := &v1beta1.Application{}
|
||||
if err := w.kubeClient.Get(ctx, types.NamespacedName{Name: appModel.Name, Namespace: appModel.Namespace}, oamApp); err != nil {
|
||||
if err := w.kubeClient.Get(ctx, types.NamespacedName{Name: converAppName(appModel.Name, envName), Namespace: appModel.Namespace}, oamApp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oamApp.Status.Workflow != nil && !oamApp.Status.Workflow.Suspend && !oamApp.Status.Workflow.Terminated && !oamApp.Status.Workflow.Finished {
|
||||
|
||||
@@ -37,20 +37,42 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
)
|
||||
|
||||
var appName = "app-workflow"
|
||||
var _ = Describe("Test workflow usecase functions", func() {
|
||||
var (
|
||||
workflowUsecase *workflowUsecaseImpl
|
||||
appUsecase *applicationUsecaseImpl
|
||||
)
|
||||
BeforeEach(func() {
|
||||
workflowUsecase = &workflowUsecaseImpl{ds: ds, kubeClient: k8sClient, apply: apply.NewAPIApplicator(k8sClient)}
|
||||
appUsecase = &applicationUsecaseImpl{ds: ds, kubeClient: k8sClient, apply: apply.NewAPIApplicator(k8sClient), envBindingUsecase: &envBindingUsecaseImpl{
|
||||
ds: ds,
|
||||
workflowUsecase: workflowUsecase,
|
||||
}}
|
||||
})
|
||||
It("Test CreateWorkflow function", func() {
|
||||
reqApp := apisv1.CreateApplicationRequest{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
Description: "this is a test app",
|
||||
EnvBinding: []*apisv1.EnvBinding{{
|
||||
Name: "dev",
|
||||
Description: "dev env",
|
||||
TargetNames: []string{"dev-target"},
|
||||
}},
|
||||
}
|
||||
_, err := appUsecase.CreateApplication(context.TODO(), reqApp)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
req := apisv1.CreateWorkflowRequest{
|
||||
Name: "test-workflow-1",
|
||||
Description: "this is a workflow",
|
||||
EnvName: "dev",
|
||||
}
|
||||
|
||||
base, err := workflowUsecase.CreateWorkflow(context.TODO(), &model.Application{
|
||||
Name: "test-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
@@ -58,10 +80,12 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
req = apisv1.CreateWorkflowRequest{
|
||||
Name: "test-workflow-2",
|
||||
Description: "this is test workflow",
|
||||
EnvName: "dev",
|
||||
Default: true,
|
||||
}
|
||||
base, err = workflowUsecase.CreateWorkflow(context.TODO(), &model.Application{
|
||||
Name: "test-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
@@ -69,7 +93,8 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
|
||||
It("Test GetApplicationDefaultWorkflow function", func() {
|
||||
workflow, err := workflowUsecase.GetApplicationDefaultWorkflow(context.TODO(), &model.Application{
|
||||
Name: "test-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(workflow).ShouldNot(BeNil())
|
||||
@@ -83,14 +108,22 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
app := &v1beta1.Application{}
|
||||
err = json.Unmarshal(raw, app)
|
||||
Expect(err).Should(BeNil())
|
||||
app.Annotations[oam.AnnotationWorkflowName] = "list-workflow-name"
|
||||
app.Annotations[oam.AnnotationWorkflowName] = "test-workflow-2"
|
||||
workflow, err := workflowUsecase.GetWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "test-workflow-2")
|
||||
Expect(err).Should(BeNil())
|
||||
for i := 0; i < 3; i++ {
|
||||
app.Annotations[oam.AnnotationPublishVersion] = fmt.Sprintf("list-workflow-name-%d", i)
|
||||
err := workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
}
|
||||
|
||||
resp, err := workflowUsecase.ListWorkflowRecords(context.TODO(), "list-workflow-name", 0, 10)
|
||||
resp, err := workflowUsecase.ListWorkflowRecords(context.TODO(), workflow, 0, 10)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(resp.Total).Should(Equal(int64(3)))
|
||||
})
|
||||
@@ -102,28 +135,35 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
app := &v1beta1.Application{}
|
||||
err = json.Unmarshal(raw, app)
|
||||
Expect(err).Should(BeNil())
|
||||
app.Annotations[oam.AnnotationWorkflowName] = "test-workflow-name"
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-name-123"
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-2-123"
|
||||
app.Annotations[oam.AnnotationDeployVersion] = "1234"
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
workflow, err := workflowUsecase.GetWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "test-workflow-2")
|
||||
Expect(err).Should(BeNil())
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
var revision = &model.ApplicationRevision{
|
||||
AppPrimaryKey: "test",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "1234",
|
||||
Status: model.RevisionStatusInit,
|
||||
DeployUser: "test-user",
|
||||
Note: "test-commit",
|
||||
TriggerType: "API",
|
||||
WorkflowName: "test-workflow-name",
|
||||
WorkflowName: "test-workflow-2",
|
||||
}
|
||||
|
||||
err = workflowUsecase.createTestApplicationRevision(context.TODO(), revision)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
detail, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), "test-workflow-name", "test-workflow-name-123")
|
||||
detail, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), workflow, "test-workflow-2-123")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(detail.WorkflowRecord.Name).Should(Equal("test-workflow-name-123"))
|
||||
Expect(detail.WorkflowRecord.Name).Should(Equal("test-workflow-2-123"))
|
||||
Expect(detail.DeployUser).Should(Equal("test-user"))
|
||||
})
|
||||
|
||||
@@ -135,19 +175,27 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
err = json.Unmarshal(raw, app)
|
||||
Expect(err).Should(BeNil())
|
||||
app.Status.Workflow.Finished = false
|
||||
app.Annotations[oam.AnnotationWorkflowName] = "test-workflow-name"
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-name-233"
|
||||
app.Annotations[oam.AnnotationWorkflowName] = "test-workflow-2"
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-2-233"
|
||||
app.Annotations[oam.AnnotationDeployVersion] = "4321"
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
workflow, err := workflowUsecase.GetWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "test-workflow-2")
|
||||
Expect(err).Should(BeNil())
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("create one revision to test sync workflow record")
|
||||
var revision = &model.ApplicationRevision{
|
||||
AppPrimaryKey: "test",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "4321",
|
||||
Status: model.RevisionStatusInit,
|
||||
DeployUser: "test-user",
|
||||
WorkflowName: "test-workflow-name",
|
||||
WorkflowName: "test-workflow-2",
|
||||
}
|
||||
err = workflowUsecase.createTestApplicationRevision(context.TODO(), revision)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -158,12 +206,17 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
err = workflowUsecase.kubeClient.Create(ctx, app)
|
||||
Expect(err).Should(BeNil())
|
||||
err = workflowUsecase.kubeClient.Status().Patch(ctx, app, client.Merge)
|
||||
|
||||
Expect(err).Should(BeNil())
|
||||
err = workflowUsecase.SyncWorkflowRecord(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
workflow, err = workflowUsecase.GetWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "test-workflow-2")
|
||||
Expect(err).Should(BeNil())
|
||||
By("check the record")
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), "test-workflow-name", "test-workflow-name-233")
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), workflow, "test-workflow-2-233")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(record.Status).Should(Equal(model.RevisionStatusComplete))
|
||||
|
||||
@@ -174,18 +227,21 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
|
||||
By("create another workflow record to test sync status from controller revision")
|
||||
app.Status.Workflow.Finished = false
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-name-111"
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "test-workflow-2-111"
|
||||
app.Annotations[oam.AnnotationDeployVersion] = "1111"
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("create another revision to test sync workflow record")
|
||||
var anotherRevision = &model.ApplicationRevision{
|
||||
AppPrimaryKey: "test",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "1111",
|
||||
Status: model.RevisionStatusInit,
|
||||
DeployUser: "test-user",
|
||||
WorkflowName: "test-workflow-name",
|
||||
WorkflowName: "test-workflow-2",
|
||||
}
|
||||
err = workflowUsecase.createTestApplicationRevision(context.TODO(), anotherRevision)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -194,9 +250,9 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
cr := &appsv1.ControllerRevision{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "record-test-test-workflow-name-111",
|
||||
Name: "record-" + appName + "-test-workflow-2-111",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"vela.io/wf-revision": "test-workflow-name-111"},
|
||||
Labels: map[string]string{"vela.io/wf-revision": "test-workflow-2-111"},
|
||||
},
|
||||
Data: runtime.RawExtension{Raw: raw},
|
||||
}
|
||||
@@ -207,7 +263,7 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("check the record")
|
||||
anotherRecord, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), "test-workflow-name", "test-workflow-name-111")
|
||||
anotherRecord, err := workflowUsecase.DetailWorkflowRecord(context.TODO(), workflow, "test-workflow-2-111")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(anotherRecord.Status).Should(Equal(model.RevisionStatusComplete))
|
||||
|
||||
@@ -219,88 +275,141 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
|
||||
It("Test ResumeRecord function", func() {
|
||||
ctx := context.TODO()
|
||||
app, err := createTestSuspendApp(ctx, "resume-app", "revision-resume1", "workflow-resume", "workflow-resume-1", workflowUsecase.kubeClient)
|
||||
|
||||
ResumeWorkflow := "resume-workflow"
|
||||
req := apisv1.CreateWorkflowRequest{
|
||||
Name: ResumeWorkflow,
|
||||
Description: "this is a workflow",
|
||||
EnvName: "resume",
|
||||
}
|
||||
|
||||
base, err := workflowUsecase.CreateWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
|
||||
app, err := createTestSuspendApp(ctx, appName, "resume", "revision-resume1", ResumeWorkflow, "workflow-resume-1", workflowUsecase.kubeClient)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, &model.Workflow{Name: ResumeWorkflow})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.createTestApplicationRevision(ctx, &model.ApplicationRevision{
|
||||
AppPrimaryKey: "resume-app",
|
||||
|
||||
Version: "revision-resume1",
|
||||
Status: model.RevisionStatusRunning,
|
||||
AppPrimaryKey: appName,
|
||||
Version: "revision-resume1",
|
||||
Status: model.RevisionStatusRunning,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.ResumeRecord(ctx, &model.Application{
|
||||
Name: "resume-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "workflow-resume-1")
|
||||
}, &model.Workflow{Name: ResumeWorkflow, EnvName: "resume"}, "workflow-resume-1")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(ctx, "workflow-resume", "workflow-resume-1")
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(ctx, &model.Workflow{Name: ResumeWorkflow, AppPrimaryKey: appName}, "workflow-resume-1")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(record.Status).Should(Equal(model.RevisionStatusRunning))
|
||||
})
|
||||
|
||||
It("Test TerminateRecord function", func() {
|
||||
ctx := context.TODO()
|
||||
app, err := createTestSuspendApp(ctx, "terminate-app", "revision-terminate1", "workflow-terminate", "workflow-terminate-1", workflowUsecase.kubeClient)
|
||||
|
||||
workflowName := "terminate-workflow"
|
||||
req := apisv1.CreateWorkflowRequest{
|
||||
Name: workflowName,
|
||||
Description: "this is a workflow",
|
||||
EnvName: "terminate",
|
||||
}
|
||||
workflow := &model.Workflow{Name: workflowName, EnvName: "terminate"}
|
||||
base, err := workflowUsecase.CreateWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
|
||||
app, err := createTestSuspendApp(ctx, appName, "terminate", "revision-terminate1", workflow.Name, "test-workflow-2-1", workflowUsecase.kubeClient)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.createTestApplicationRevision(ctx, &model.ApplicationRevision{
|
||||
AppPrimaryKey: "terminate-app",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "revision-terminate1",
|
||||
Status: model.RevisionStatusRunning,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.TerminateRecord(ctx, &model.Application{
|
||||
Name: "terminate-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "workflow-terminate-1")
|
||||
}, workflow, "test-workflow-2-1")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(ctx, "workflow-terminate", "workflow-terminate-1")
|
||||
record, err := workflowUsecase.DetailWorkflowRecord(ctx, workflow, "test-workflow-2-1")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(record.Status).Should(Equal(model.RevisionStatusTerminated))
|
||||
})
|
||||
|
||||
It("Test RollbackRecord function", func() {
|
||||
ctx := context.TODO()
|
||||
app, err := createTestSuspendApp(ctx, "rollback-app", "revision-rollback1", "workflow-rollback", "workflow-rollback-1", workflowUsecase.kubeClient)
|
||||
|
||||
workflowName := "rollback-workflow"
|
||||
req := apisv1.CreateWorkflowRequest{
|
||||
Name: workflowName,
|
||||
Description: "this is a workflow",
|
||||
EnvName: "rollback",
|
||||
}
|
||||
workflow := &model.Workflow{Name: workflowName, EnvName: "rollback"}
|
||||
base, err := workflowUsecase.CreateWorkflow(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
|
||||
app, err := createTestSuspendApp(ctx, appName, "rollback", "revision-rollback1", workflow.Name, "test-workflow-2-2", workflowUsecase.kubeClient)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.createTestApplicationRevision(ctx, &model.ApplicationRevision{
|
||||
AppPrimaryKey: "rollback-app",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "revision-rollback1",
|
||||
Status: model.RevisionStatusRunning,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
err = workflowUsecase.createTestApplicationRevision(ctx, &model.ApplicationRevision{
|
||||
AppPrimaryKey: "rollback-app",
|
||||
AppPrimaryKey: appName,
|
||||
Version: "revision-rollback0",
|
||||
ApplyAppConfig: `{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"annotations":{"app.oam.dev/workflowName":"workflow-rollback","app.oam.dev/deployVersion":"revision-rollback1","vela.io/publish-version":"workflow-rollback1"},"name":"first-vela-app","namespace":"default"},"spec":{"components":[{"name":"express-server","properties":{"image":"crccheck/hello-world","port":8000},"traits":[{"properties":{"domain":"testsvc.example.com","http":{"/":8000}},"type":"ingress-1-20"}],"type":"webservice"}]}}`,
|
||||
ApplyAppConfig: `{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"annotations":{"app.oam.dev/workflowName":"test-workflow-2-2","app.oam.dev/deployVersion":"revision-rollback1","vela.io/publish-version":"workflow-rollback1"},"name":"first-vela-app","namespace":"default"},"spec":{"components":[{"name":"express-server","properties":{"image":"crccheck/hello-world","port":8000},"traits":[{"properties":{"domain":"testsvc.example.com","http":{"/":8000}},"type":"ingress-1-20"}],"type":"webservice"}]}}`,
|
||||
Status: model.RevisionStatusComplete,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.RollbackRecord(ctx, &model.Application{
|
||||
Name: "rollback-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "workflow-rollback-1", "revision-rollback0")
|
||||
}, workflow, "test-workflow-2-2", "revision-rollback0")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
recordsNum, err := workflowUsecase.ds.Count(ctx, &model.WorkflowRecord{
|
||||
AppPrimaryKey: "rollback-app",
|
||||
WorkflowPrimaryKey: "workflow-rollback",
|
||||
AppPrimaryKey: appName,
|
||||
WorkflowName: workflow.Name,
|
||||
RevisionPrimaryKey: "revision-rollback0",
|
||||
}, nil)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -308,18 +417,21 @@ var _ = Describe("Test workflow usecase functions", func() {
|
||||
|
||||
By("rollback application without revision version")
|
||||
app.Annotations[oam.AnnotationPublishVersion] = "workflow-rollback-2"
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), app)
|
||||
err = workflowUsecase.CreateWorkflowRecord(context.TODO(), &model.Application{
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, app, workflow)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = workflowUsecase.RollbackRecord(ctx, &model.Application{
|
||||
Name: "rollback-app",
|
||||
Name: appName,
|
||||
Namespace: "default",
|
||||
}, "workflow-rollback-2", "")
|
||||
}, workflow, "workflow-rollback-2", "")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
recordsNum, err = workflowUsecase.ds.Count(ctx, &model.WorkflowRecord{
|
||||
AppPrimaryKey: "rollback-app",
|
||||
WorkflowPrimaryKey: "workflow-rollback",
|
||||
AppPrimaryKey: appName,
|
||||
WorkflowName: workflow.Name,
|
||||
RevisionPrimaryKey: "revision-rollback0",
|
||||
}, nil)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -331,10 +443,11 @@ var yamlStr = `apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/workflowName: test-workflow-name
|
||||
app.oam.dev/workflowName: test-workflow-2
|
||||
app.oam.dev/deployVersion: "1234"
|
||||
vela.io/publish-version: "test-workflow-name-111"
|
||||
name: test
|
||||
app.oam.dev/publishVersion: "test-workflow-name-111"
|
||||
app.oam.dev/appName: "app-workflow"
|
||||
name: app-workflow-dev
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
|
||||
@@ -66,3 +66,12 @@ var ErrTraitNotExist = NewBcode(400, 10015, "trait is not exist")
|
||||
|
||||
// ErrTraitAlreadyExist trait is already exist
|
||||
var ErrTraitAlreadyExist = NewBcode(400, 10016, "trait is already exist")
|
||||
|
||||
// ErrApplicationNoReadyRevision application not have ready revision
|
||||
var ErrApplicationNoReadyRevision = NewBcode(400, 10017, "application not have ready revision")
|
||||
|
||||
// ErrApplicationRevisionNotExist application revision is not exist
|
||||
var ErrApplicationRevisionNotExist = NewBcode(404, 10018, "application revision is not exist")
|
||||
|
||||
// ErrApplicationRefusedDelete The application cannot be deleted because it has been deployed
|
||||
var ErrApplicationRefusedDelete = NewBcode(400, 10019, "The application cannot be deleted because it has been deployed")
|
||||
|
||||
@@ -27,3 +27,9 @@ var ErrWorkflowNoDefault = NewBcode(404, 20004, "application default workflow is
|
||||
|
||||
// ErrMustQueryByApp you can only query the Workflow list based on applications.
|
||||
var ErrMustQueryByApp = NewBcode(404, 20005, "you can only query the Workflow list based on applications.")
|
||||
|
||||
// ErrWorkflowNoEnv workflow have not env
|
||||
var ErrWorkflowNoEnv = NewBcode(400, 20006, "workflow must set env name")
|
||||
|
||||
// ErrWorkflowRecordNotExist workflow record is not exist
|
||||
var ErrWorkflowRecordNotExist = NewBcode(404, 20007, "workflow record is not exist")
|
||||
|
||||
@@ -5,7 +5,7 @@ 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
|
||||
http://wwc.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,
|
||||
@@ -32,13 +32,18 @@ import (
|
||||
)
|
||||
|
||||
type applicationWebService struct {
|
||||
workflowWebService
|
||||
applicationUsecase usecase.ApplicationUsecase
|
||||
envBindingUsecase usecase.EnvBindingUsecase
|
||||
}
|
||||
|
||||
// NewApplicationWebService new application manage webservice
|
||||
func NewApplicationWebService(applicationUsecase usecase.ApplicationUsecase, envBindingUsecase usecase.EnvBindingUsecase) WebService {
|
||||
func NewApplicationWebService(applicationUsecase usecase.ApplicationUsecase, envBindingUsecase usecase.EnvBindingUsecase, workflowUsecase usecase.WorkflowUsecase) WebService {
|
||||
return &applicationWebService{
|
||||
workflowWebService: workflowWebService{
|
||||
workflowUsecase: workflowUsecase,
|
||||
applicationUsecase: applicationUsecase,
|
||||
},
|
||||
applicationUsecase: applicationUsecase,
|
||||
envBindingUsecase: envBindingUsecase,
|
||||
}
|
||||
@@ -89,15 +94,23 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailApplicationResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/envs/{envName}/status").To(c.getApplicationStatus).
|
||||
Doc("get application status").
|
||||
ws.Route(ws.PUT("/{name}").To(c.updateApplication).
|
||||
Doc("update one application ").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application ").DataType("string")).
|
||||
Param(ws.PathParameter("envName", "identifier of the application envbinding").DataType("string")).
|
||||
Returns(200, "", apis.ApplicationStatusResponse{}).
|
||||
Reads(apis.UpdateApplicationRequest{}).
|
||||
Returns(200, "", apis.ApplicationBase{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.ApplicationStatusResponse{}))
|
||||
Writes(apis.ApplicationBase{}))
|
||||
ws.Route(ws.GET("/{name}/statistics").To(c.applicationStatistics).
|
||||
Doc("detail one application ").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application ").DataType("string")).
|
||||
Returns(200, "", apis.ApplicationStatisticsResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.ApplicationStatisticsResponse{}))
|
||||
|
||||
ws.Route(ws.PUT("/{name}").To(c.updateApplication).
|
||||
Doc("update one application ").
|
||||
@@ -149,7 +162,7 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
Writes(apis.ComponentBase{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/components/{componentName}").To(c.detailComponent).
|
||||
Doc("detail component for application ").
|
||||
Doc("detail component for application ").
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application ").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
@@ -157,6 +170,17 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailComponentResponse{}))
|
||||
|
||||
ws.Route(ws.PUT("/{name}/components/{componentName}").To(c.updateComponent).
|
||||
Doc("update component config").
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.componentCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Reads(apis.UpdateApplicationComponentRequest{}).
|
||||
Returns(200, "", apis.ComponentBase{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.ComponentBase{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/policies").To(c.listApplicationPolicies).
|
||||
Doc("list policy for application").
|
||||
Filter(c.appCheckFilter).
|
||||
@@ -210,6 +234,7 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
ws.Route(ws.POST("/{name}/components/{compName}/traits").To(c.addApplicationTrait).
|
||||
Doc("add trait for a component").
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.componentCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
|
||||
Param(ws.PathParameter("compName", "identifier of the component").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
@@ -221,6 +246,7 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
ws.Route(ws.PUT("/{name}/components/{compName}/traits/{traitType}").To(c.updateApplicationTrait).
|
||||
Doc("update trait from a component").
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.componentCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
|
||||
Param(ws.PathParameter("compName", "identifier of the component").DataType("string")).
|
||||
Param(ws.PathParameter("traitType", "identifier of the type of trait").DataType("string")).
|
||||
@@ -233,6 +259,7 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
ws.Route(ws.DELETE("/{name}/components/{compName}/traits/{traitType}").To(c.deleteApplicationTrait).
|
||||
Doc("delete trait from a component").
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.componentCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
|
||||
Param(ws.PathParameter("compName", "identifier of the component").DataType("string")).
|
||||
Param(ws.PathParameter("traitType", "identifier of the type of trait").DataType("string")).
|
||||
@@ -306,6 +333,138 @@ func (c *applicationWebService) GetWebService() *restful.WebService {
|
||||
Returns(404, "", bcode.Bcode{}).
|
||||
Writes(apis.EmptyResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/envs/{envName}/status").To(c.getApplicationStatus).
|
||||
Doc("get application status").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.envCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application ").DataType("string")).
|
||||
Param(ws.PathParameter("envName", "identifier of the application envbinding").DataType("string")).
|
||||
Returns(200, "", apis.ApplicationStatusResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.ApplicationStatusResponse{}))
|
||||
|
||||
ws.Route(ws.POST("/{name}/envs/{envName}/recycle").To(c.recycleApplicationEnv).
|
||||
Doc("get application status").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.envCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application ").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("envName", "identifier of the application envbinding").DataType("string").Required(true)).
|
||||
Returns(200, "", apis.EmptyResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.EmptyResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows").To(c.listApplicationWorkflows).
|
||||
Doc("list application workflow").
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.ListWorkflowResponse{}).
|
||||
Writes(apis.ListWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.POST("/{name}/workflows").To(c.createApplicationWorkflow).
|
||||
Doc("create application workflow").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Reads(apis.CreateWorkflowRequest{}).
|
||||
Filter(c.appCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Returns(200, "create success", apis.DetailWorkflowResponse{}).
|
||||
Returns(400, "create failure", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}").To(c.detailWorkflow).
|
||||
Doc("detail application workflow").
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workfloc.").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Returns(200, "create success", apis.DetailWorkflowResponse{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.PUT("/{name}/workflows/{workflowName}").To(c.updateWorkflow).
|
||||
Doc("update application workflow config").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Reads(apis.UpdateWorkflowRequest{}).
|
||||
Returns(200, "", apis.DetailWorkflowResponse{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.DELETE("/{name}/workflows/{workflowName}").To(c.deleteWorkflow).
|
||||
Doc("deletet workflow").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Returns(200, "", apis.EmptyResponse{}).
|
||||
Writes(apis.EmptyResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}/records").To(c.listWorkflowRecords).
|
||||
Doc("query application workflow execution record").
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Param(ws.QueryParameter("page", "query the page number").DataType("integer")).
|
||||
Param(ws.QueryParameter("pageSize", "query the page size number").DataType("integer")).
|
||||
Returns(200, "", apis.ListWorkflowRecordsResponse{}).
|
||||
Writes(apis.ListWorkflowRecordsResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}/records/{record}").To(c.detailWorkflowRecord).
|
||||
Doc("query application workflow execution record detail").
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Returns(200, "", apis.DetailWorkflowRecordResponse{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}/records/{record}/resume").To(c.resumeWorkflowRecord).
|
||||
Doc("resume suspend workflow record").
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}/records/{record}/terminate").To(c.terminateWorkflowRecord).
|
||||
Doc("terminate suspend workflow record").
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/workflows/{workflowName}/records/{record}/rollback").To(c.rollbackWorkflowRecord).
|
||||
Doc("rollback suspend application record").
|
||||
Param(ws.PathParameter("name", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workflowName", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Param(ws.QueryParameter("rollbackVersion", "identifier of the rollback revision").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.appCheckFilter).
|
||||
Filter(c.workflowCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
|
||||
return ws
|
||||
}
|
||||
|
||||
@@ -465,6 +624,30 @@ func (c *applicationWebService) detailComponent(req *restful.Request, res *restf
|
||||
}
|
||||
}
|
||||
|
||||
func (c *applicationWebService) updateComponent(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
component := req.Request.Context().Value(&apis.CtxKeyApplicationComponent).(*model.ApplicationComponent)
|
||||
// Verify the validity of parameters
|
||||
var updateReq apis.UpdateApplicationComponentRequest
|
||||
if err := req.ReadEntity(&updateReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := validate.Struct(&updateReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
base, err := c.applicationUsecase.UpdateComponent(req.Request.Context(), app, component, updateReq)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(base); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *applicationWebService) createApplicationPolicy(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
// Verify the validity of parameters
|
||||
@@ -641,7 +824,7 @@ func (c *applicationWebService) getApplicationStatus(req *restful.Request, res *
|
||||
return
|
||||
}
|
||||
|
||||
if err := res.WriteEntity(apis.ApplicationStatusResponse{Status: status}); err != nil {
|
||||
if err := res.WriteEntity(apis.ApplicationStatusResponse{Status: status, EnvName: req.PathParameter("envName")}); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
@@ -759,6 +942,17 @@ func (c *applicationWebService) appCheckFilter(req *restful.Request, res *restfu
|
||||
chain.ProcessFilter(req, res)
|
||||
}
|
||||
|
||||
func (c *applicationWebService) componentCheckFilter(req *restful.Request, res *restful.Response, chain *restful.FilterChain) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
component, err := c.applicationUsecase.GetApplicationComponent(req.Request.Context(), app, req.PathParameter("compName"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
req.Request = req.Request.WithContext(context.WithValue(req.Request.Context(), &apis.CtxKeyApplicationComponent, component))
|
||||
chain.ProcessFilter(req, res)
|
||||
}
|
||||
|
||||
func (c *applicationWebService) envCheckFilter(req *restful.Request, res *restful.Response, chain *restful.FilterChain) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
envBindings, err := c.envBindingUsecase.GetEnvBindings(req.Request.Context(), app)
|
||||
@@ -775,3 +969,30 @@ func (c *applicationWebService) envCheckFilter(req *restful.Request, res *restfu
|
||||
}
|
||||
bcode.ReturnError(req, res, bcode.ErrApplicationNotEnv)
|
||||
}
|
||||
|
||||
func (c *applicationWebService) applicationStatistics(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
detail, err := c.applicationUsecase.Statistics(req.Request.Context(), app)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(detail); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *applicationWebService) recycleApplicationEnv(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
env := req.Request.Context().Value(&apis.CtxKeyApplicationEnvBinding).(*model.EnvBinding)
|
||||
err := c.envBindingUsecase.ApplicationEnvRecycle(req.Request.Context(), app, env)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(apis.EmptyResponse{}); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ func (dt *DeliveryTargetWebService) updateDeliveryTarget(req *restful.Request, r
|
||||
func (dt *DeliveryTargetWebService) deleteDeliveryTarget(req *restful.Request, res *restful.Response) {
|
||||
deliveryTargetName := req.PathParameter("name")
|
||||
// deliveryTarget in use, can't be deleted
|
||||
applications, err := dt.applicationUsecase.ListApplications(context.TODO(), apis.ListApplicatioOptions{TargetName: deliveryTargetName})
|
||||
applications, err := dt.applicationUsecase.ListApplications(req.Request.Context(), apis.ListApplicatioOptions{TargetName: deliveryTargetName})
|
||||
if err != nil {
|
||||
if !errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
bcode.ReturnError(req, res, err)
|
||||
|
||||
@@ -69,14 +69,13 @@ func Init(ds datastore.DataStore) {
|
||||
envBindingUsecase := usecase.NewEnvBindingUsecase(ds, workflowUsecase)
|
||||
applicationUsecase := usecase.NewApplicationUsecase(ds, workflowUsecase, envBindingUsecase, deliveryTargetUsecase)
|
||||
RegistWebService(NewClusterWebService(clusterUsecase))
|
||||
RegistWebService(NewApplicationWebService(applicationUsecase, envBindingUsecase))
|
||||
RegistWebService(NewApplicationWebService(applicationUsecase, envBindingUsecase, workflowUsecase))
|
||||
RegistWebService(NewNamespaceWebService(namespaceUsecase))
|
||||
RegistWebService(NewDefinitionWebservice(definitionUsecase))
|
||||
RegistWebService(NewAddonWebService(addonUsecase))
|
||||
RegistWebService(NewAddonRegistryWebService(addonUsecase))
|
||||
RegistWebService(NewOAMApplication(oamApplicationUsecase))
|
||||
RegistWebService(&policyDefinitionWebservice{})
|
||||
RegistWebService(NewWorkflowWebService(workflowUsecase, applicationUsecase))
|
||||
RegistWebService(NewDeliveryTargetWebService(deliveryTargetUsecase, applicationUsecase))
|
||||
RegistWebService(NewVelaQLWebService(velaQLUsecase))
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ package webservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
@@ -31,122 +29,14 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
|
||||
)
|
||||
|
||||
// NewWorkflowWebService new workflow webservice
|
||||
func NewWorkflowWebService(workflowUsecase usecase.WorkflowUsecase, applicationUsecase usecase.ApplicationUsecase) WebService {
|
||||
return &workflowWebService{
|
||||
workflowUsecase: workflowUsecase,
|
||||
applicationUsecase: applicationUsecase,
|
||||
}
|
||||
}
|
||||
|
||||
type workflowWebService struct {
|
||||
workflowUsecase usecase.WorkflowUsecase
|
||||
applicationUsecase usecase.ApplicationUsecase
|
||||
}
|
||||
|
||||
func (w *workflowWebService) GetWebService() *restful.WebService {
|
||||
ws := new(restful.WebService)
|
||||
ws.Path(versionPrefix+"/workflows").
|
||||
Consumes(restful.MIME_XML, restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON, restful.MIME_XML).
|
||||
Doc("api for cluster manage")
|
||||
|
||||
tags := []string{"workflow"}
|
||||
|
||||
ws.Route(ws.GET("/").To(w.listApplicationWorkflows).
|
||||
Doc("list application workflow").
|
||||
Param(ws.QueryParameter("appName", "identifier of the application.").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("enable", "query based on enable status").DataType("boolean")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.ListWorkflowResponse{}).
|
||||
Writes(apis.ListWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.POST("/").To(w.createApplicationWorkflow).
|
||||
Doc("create application workflow").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Reads(apis.CreateWorkflowRequest{}).
|
||||
Returns(200, "create success", apis.DetailWorkflowResponse{}).
|
||||
Returns(400, "create failure", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}").To(w.detailWorkflow).
|
||||
Doc("detail application workflow").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow.").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.workflowCheckFilter).
|
||||
Returns(200, "create success", apis.DetailWorkflowResponse{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.PUT("/{name}").To(w.updateWorkflow).
|
||||
Doc("update application workflow config").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.workflowCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Reads(apis.UpdateWorkflowRequest{}).
|
||||
Returns(200, "", apis.DetailWorkflowResponse{}).
|
||||
Writes(apis.DetailWorkflowResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.DELETE("/{name}").To(w.deleteWorkflow).
|
||||
Doc("deletet workflow").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.workflowCheckFilter).
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Returns(200, "", apis.EmptyResponse{}).
|
||||
Writes(apis.EmptyResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/records").To(w.listWorkflowRecords).
|
||||
Doc("query application workflow execution record").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.workflowCheckFilter).
|
||||
Param(ws.QueryParameter("page", "query the page number").DataType("integer")).
|
||||
Param(ws.QueryParameter("pageSize", "query the page size number").DataType("integer")).
|
||||
Returns(200, "", apis.ListWorkflowRecordsResponse{}).
|
||||
Writes(apis.ListWorkflowRecordsResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/records/{record}").To(w.detailWorkflowRecord).
|
||||
Doc("query application workflow execution record detail").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.DetailWorkflowRecordResponse{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}).Do(returns200, returns500))
|
||||
|
||||
ws.Route(ws.GET("/{name}/records/{record}/resume").To(w.resumeWorkflowRecord).
|
||||
Doc("resume suspend workflow record").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.applicationCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/records/{record}/terminate").To(w.terminateWorkflowRecord).
|
||||
Doc("terminate suspend workflow record").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.applicationCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/{name}/records/{record}/rollback").To(w.rollbackWorkflowRecord).
|
||||
Doc("rollback suspend application record").
|
||||
Param(ws.PathParameter("name", "identifier of the workflow").DataType("string")).
|
||||
Param(ws.PathParameter("record", "identifier of the workflow record").DataType("string")).
|
||||
Param(ws.QueryParameter("rollbackVersion", "identifier of the rollback revision").DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(w.applicationCheckFilter).
|
||||
Returns(200, "", nil).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DetailWorkflowRecordResponse{}))
|
||||
return ws
|
||||
}
|
||||
|
||||
func (w *workflowWebService) workflowCheckFilter(req *restful.Request, res *restful.Response, chain *restful.FilterChain) {
|
||||
workflow, err := w.workflowUsecase.GetWorkflow(req.Request.Context(), req.PathParameter("name"))
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
workflow, err := w.workflowUsecase.GetWorkflow(req.Request.Context(), app, req.PathParameter("workflowName"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -156,37 +46,19 @@ func (w *workflowWebService) workflowCheckFilter(req *restful.Request, res *rest
|
||||
}
|
||||
|
||||
func (w *workflowWebService) applicationCheckFilter(req *restful.Request, res *restful.Response, chain *restful.FilterChain) {
|
||||
workflow, err := w.workflowUsecase.GetWorkflow(req.Request.Context(), req.PathParameter("name"))
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
workflow, err := w.workflowUsecase.GetWorkflow(req.Request.Context(), app, req.PathParameter("workflowName"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
|
||||
app, err := w.applicationUsecase.GetApplication(req.Request.Context(), workflow.AppPrimaryKey)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
req.Request = req.Request.WithContext(context.WithValue(req.Request.Context(), &apis.CtxKeyApplication, app))
|
||||
req.Request = req.Request.WithContext(context.WithValue(req.Request.Context(), &apis.CtxKeyWorkflow, workflow))
|
||||
chain.ProcessFilter(req, res)
|
||||
}
|
||||
|
||||
func (w *workflowWebService) listApplicationWorkflows(req *restful.Request, res *restful.Response) {
|
||||
if req.QueryParameter("appName") == "" {
|
||||
bcode.ReturnError(req, res, bcode.ErrMustQueryByApp)
|
||||
return
|
||||
}
|
||||
app, err := w.applicationUsecase.GetApplication(req.Request.Context(), req.QueryParameter("appName"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
var enableQuery *bool
|
||||
enable, err := strconv.ParseBool(req.QueryParameter("enable"))
|
||||
if err == nil {
|
||||
enableQuery = &enable
|
||||
}
|
||||
workflows, err := w.workflowUsecase.ListApplicationWorkflow(req.Request.Context(), app, enableQuery)
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
workflows, err := w.workflowUsecase.ListApplicationWorkflow(req.Request.Context(), app)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -265,7 +137,8 @@ func (w *workflowWebService) updateWorkflow(req *restful.Request, res *restful.R
|
||||
}
|
||||
|
||||
func (w *workflowWebService) deleteWorkflow(req *restful.Request, res *restful.Response) {
|
||||
if err := w.workflowUsecase.DeleteWorkflow(req.Request.Context(), req.PathParameter("name")); err != nil {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
if err := w.workflowUsecase.DeleteWorkflow(req.Request.Context(), app, req.PathParameter("workflowName")); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
@@ -281,8 +154,8 @@ func (w *workflowWebService) listWorkflowRecords(req *restful.Request, res *rest
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
|
||||
records, err := w.workflowUsecase.ListWorkflowRecords(req.Request.Context(), req.PathParameter("name"), page, pageSize)
|
||||
workflow := req.Request.Context().Value(&apis.CtxKeyWorkflow).(*model.Workflow)
|
||||
records, err := w.workflowUsecase.ListWorkflowRecords(req.Request.Context(), workflow, page, pageSize)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -295,7 +168,8 @@ func (w *workflowWebService) listWorkflowRecords(req *restful.Request, res *rest
|
||||
}
|
||||
|
||||
func (w *workflowWebService) detailWorkflowRecord(req *restful.Request, res *restful.Response) {
|
||||
record, err := w.workflowUsecase.DetailWorkflowRecord(req.Request.Context(), req.PathParameter("name"), req.PathParameter("record"))
|
||||
workflow := req.Request.Context().Value(&apis.CtxKeyWorkflow).(*model.Workflow)
|
||||
record, err := w.workflowUsecase.DetailWorkflowRecord(req.Request.Context(), workflow, req.PathParameter("record"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -309,7 +183,8 @@ func (w *workflowWebService) detailWorkflowRecord(req *restful.Request, res *res
|
||||
|
||||
func (w *workflowWebService) resumeWorkflowRecord(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
err := w.workflowUsecase.ResumeRecord(req.Request.Context(), app, req.PathParameter("record"))
|
||||
workflow := req.Request.Context().Value(&apis.CtxKeyWorkflow).(*model.Workflow)
|
||||
err := w.workflowUsecase.ResumeRecord(req.Request.Context(), app, workflow, req.PathParameter("record"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -319,7 +194,8 @@ func (w *workflowWebService) resumeWorkflowRecord(req *restful.Request, res *res
|
||||
|
||||
func (w *workflowWebService) terminateWorkflowRecord(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
err := w.workflowUsecase.TerminateRecord(req.Request.Context(), app, req.PathParameter("record"))
|
||||
workflow := req.Request.Context().Value(&apis.CtxKeyWorkflow).(*model.Workflow)
|
||||
err := w.workflowUsecase.TerminateRecord(req.Request.Context(), app, workflow, req.PathParameter("record"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
@@ -329,7 +205,8 @@ func (w *workflowWebService) terminateWorkflowRecord(req *restful.Request, res *
|
||||
|
||||
func (w *workflowWebService) rollbackWorkflowRecord(req *restful.Request, res *restful.Response) {
|
||||
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
|
||||
err := w.workflowUsecase.RollbackRecord(req.Request.Context(), app, req.PathParameter("record"), req.QueryParameter("rollbackVersion"))
|
||||
workflow := req.Request.Context().Value(&apis.CtxKeyWorkflow).(*model.Workflow)
|
||||
err := w.workflowUsecase.RollbackRecord(req.Request.Context(), app, workflow, req.PathParameter("record"), req.QueryParameter("rollbackVersion"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
|
||||
+7
-1
@@ -133,11 +133,17 @@ const (
|
||||
AnnotationDeployVersion = "app.oam.dev/deployVersion"
|
||||
|
||||
// AnnotationPublishVersion is annotation that record the application workflow version.
|
||||
AnnotationPublishVersion = "vela.io/publish-version"
|
||||
AnnotationPublishVersion = "app.oam.dev/publishVersion"
|
||||
|
||||
// AnnotationWorkflowName specifies the workflow name for execution.
|
||||
AnnotationWorkflowName = "app.oam.dev/workflowName"
|
||||
|
||||
// AnnotationAppName specifies the name for application in db.
|
||||
AnnotationAppName = "app.oam.dev/appName"
|
||||
|
||||
// AnnotationAppAlias specifies the alias for application in db.
|
||||
AnnotationAppAlias = "app.oam.dev/appAlias"
|
||||
|
||||
// AnnotationWorkloadGVK indicates the managed workload's GVK by trait
|
||||
AnnotationWorkloadGVK = "trait.oam.dev/workload-gvk"
|
||||
|
||||
|
||||
@@ -33,12 +33,15 @@ import (
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
)
|
||||
|
||||
var appName = "app-e2e"
|
||||
var appProject = "test-app-project"
|
||||
|
||||
var _ = Describe("Test application rest api", func() {
|
||||
It("Test create app", func() {
|
||||
defer GinkgoRecover()
|
||||
var req = apisv1.CreateApplicationRequest{
|
||||
Name: "test-app-sadasd",
|
||||
Namespace: "test-app-namespace",
|
||||
Name: appName,
|
||||
Namespace: appProject,
|
||||
Description: "this is a test app",
|
||||
Icon: "",
|
||||
Labels: map[string]string{"test": "true"},
|
||||
@@ -63,7 +66,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test delete app", func() {
|
||||
defer GinkgoRecover()
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/test-app-sadasd", nil)
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/"+appName, nil)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
@@ -76,8 +79,8 @@ var _ = Describe("Test application rest api", func() {
|
||||
bs, err := ioutil.ReadFile("./testdata/example-app.yaml")
|
||||
Expect(err).Should(Succeed())
|
||||
var req = apisv1.CreateApplicationRequest{
|
||||
Name: "test-app-sadasd",
|
||||
Namespace: "test-app-namespace",
|
||||
Name: appName,
|
||||
Namespace: appProject,
|
||||
Description: "this is a test app",
|
||||
Icon: "",
|
||||
Labels: map[string]string{"test": "true"},
|
||||
@@ -102,7 +105,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test list components", func() {
|
||||
defer GinkgoRecover()
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components")
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/" + appName + "/components")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -114,37 +117,9 @@ var _ = Describe("Test application rest api", func() {
|
||||
Expect(cmp.Diff(len(components.Components), 2)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test list policies", func() {
|
||||
defer GinkgoRecover()
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
Expect(res.Body).ShouldNot(BeNil())
|
||||
defer res.Body.Close()
|
||||
var policies apisv1.ListApplicationPolicy
|
||||
err = json.NewDecoder(res.Body).Decode(&policies)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(cmp.Diff(len(policies.Policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test get workflow", func() {
|
||||
// defer GinkgoRecover()
|
||||
// res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies")
|
||||
// Expect(err).ShouldNot(HaveOccurred())
|
||||
// Expect(res).ShouldNot(BeNil())
|
||||
// Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
// Expect(res.Body).ShouldNot(BeNil())
|
||||
// defer res.Body.Close()
|
||||
// var policies apisv1.ListApplicationPolicy
|
||||
// err = json.NewDecoder(res.Body).Decode(&policies)
|
||||
// Expect(err).ShouldNot(HaveOccurred())
|
||||
// Expect(cmp.Diff(len(policies.Policies), 1)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test detail application", func() {
|
||||
defer GinkgoRecover()
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd")
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/" + appName)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -153,19 +128,53 @@ var _ = Describe("Test application rest api", func() {
|
||||
var detail apisv1.DetailApplicationResponse
|
||||
err = json.NewDecoder(res.Body).Decode(&detail)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(cmp.Diff(len(detail.Policies), 1)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(len(detail.Policies), 0)).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test deploy application", func() {
|
||||
defer GinkgoRecover()
|
||||
var req = apisv1.ApplicationDeployRequest{
|
||||
Note: "test apply",
|
||||
TriggerType: "web",
|
||||
Force: false,
|
||||
var targetName = "dev-default"
|
||||
var envName = "dev"
|
||||
var namespace = "default"
|
||||
// create target
|
||||
var createTarget = apisv1.CreateDeliveryTargetRequest{
|
||||
Name: targetName,
|
||||
Namespace: appProject,
|
||||
Cluster: &apisv1.ClusterTarget{
|
||||
ClusterName: "local",
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
bodyByte, err := json.Marshal(req)
|
||||
bodyByte, err := json.Marshal(createTarget)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/deploy", "application/json", bytes.NewBuffer(bodyByte))
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/deliveryTargets", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
|
||||
// create env
|
||||
var createEnvReq = apisv1.CreateApplicationEnvRequest{
|
||||
EnvBinding: apisv1.EnvBinding{
|
||||
Name: envName,
|
||||
TargetNames: []string{targetName},
|
||||
},
|
||||
}
|
||||
bodyByte, err = json.Marshal(createEnvReq)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err = http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/envs", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
|
||||
// deploy app
|
||||
var req = apisv1.ApplicationDeployRequest{
|
||||
Note: "test apply",
|
||||
TriggerType: "web",
|
||||
WorkflowName: "dev",
|
||||
Force: false,
|
||||
}
|
||||
bodyByte, err = json.Marshal(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err = http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/deploy", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -177,7 +186,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
Expect(cmp.Diff(response.Status, model.RevisionStatusRunning)).Should(BeEmpty())
|
||||
|
||||
var oam v1beta1.Application
|
||||
err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: "test-app-sadasd", Namespace: "test-app-namespace"}, &oam)
|
||||
err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: appName + "-" + envName, Namespace: appProject}, &oam)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(len(oam.Spec.Components), 2)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(len(oam.Spec.Policies), 1)).Should(BeEmpty())
|
||||
@@ -195,7 +204,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte, err := json.Marshal(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components", "application/json", bytes.NewBuffer(bodyByte))
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/components", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -209,7 +218,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test detail component", func() {
|
||||
defer GinkgoRecover()
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components/test2")
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/" + appName + "/components/test2")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -229,7 +238,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte, err := json.Marshal(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components/test2/traits", "application/json", bytes.NewBuffer(bodyByte))
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/components/test2/traits", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -249,7 +258,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte, err := json.Marshal(req2)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components/test2/traits/ingress", bytes.NewBuffer(bodyByte))
|
||||
req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/api/v1/applications/"+appName+"/components/test2/traits/ingress", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
@@ -266,7 +275,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test delete trait", func() {
|
||||
defer GinkgoRecover()
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/components/test2/traits/ingress", nil)
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/"+appName+"/components/test2/traits/ingress", nil)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
@@ -283,7 +292,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte, err := json.Marshal(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies", "application/json", bytes.NewBuffer(bodyByte))
|
||||
res, err := http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/policies", "application/json", bytes.NewBuffer(bodyByte))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 400)).Should(BeEmpty())
|
||||
@@ -295,7 +304,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte2, err := json.Marshal(req2)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err = http.Post("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies", "application/json", bytes.NewBuffer(bodyByte2))
|
||||
res, err = http.Post("http://127.0.0.1:8000/api/v1/applications/"+appName+"/policies", "application/json", bytes.NewBuffer(bodyByte2))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -310,7 +319,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test detail application policy", func() {
|
||||
defer GinkgoRecover()
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies/test2")
|
||||
res, err := http.Get("http://127.0.0.1:8000/api/v1/applications/" + appName + "/policies/test2")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
|
||||
@@ -330,7 +339,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
}
|
||||
bodyByte2, err := json.Marshal(req2)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies/test2", bytes.NewBuffer(bodyByte2))
|
||||
req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/api/v1/applications/"+appName+"/policies/test2", bytes.NewBuffer(bodyByte2))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
@@ -348,7 +357,7 @@ var _ = Describe("Test application rest api", func() {
|
||||
|
||||
It("Test delete application policy", func() {
|
||||
defer GinkgoRecover()
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/test-app-sadasd/policies/test2", nil)
|
||||
req, err := http.NewRequest(http.MethodDelete, "http://127.0.0.1:8000/api/v1/applications/"+appName+"/policies/test2", nil)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
@@ -60,7 +60,7 @@ var _ = BeforeSuite(func() {
|
||||
}
|
||||
cfg.LeaderConfig.ID = uuid.New().String()
|
||||
cfg.LeaderConfig.LockName = "apiserver-lock"
|
||||
cfg.LeaderConfig.Duration = time.Second * 5
|
||||
cfg.LeaderConfig.Duration = time.Second * 10
|
||||
|
||||
server, err := arest.New(cfg)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
Reference in New Issue
Block a user