Compare commits

...

7 Commits

Author SHA1 Message Date
github-actions[bot]
492e7d7f0d [Backport release-1.7] Fix: use the namespace specified in the resource if -n is not s… (#5396)
* fix #5368, use the namespace specified in the resource if -n is not specified

Signed-off-by: Basuotian <basuoluomiu@gmail.com>
(cherry picked from commit 47c9b4457b)

* add default namespace for the case missing namespace in resourceRef

Signed-off-by: Basuotian <basuoluomiu@gmail.com>
(cherry picked from commit 3ae0657796)

* add test case

Signed-off-by: Basuotian <basuoluomiu@gmail.com>
(cherry picked from commit 4ba5eb88eb)

---------

Co-authored-by: Basuotian <basuoluomiu@gmail.com>
2023-01-31 20:16:18 +08:00
Jianbo Sun
0742ca9ee5 Fix: aligin config create to be managed by apps with Dispatch function (#5384) (#5394)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2023-01-31 18:04:36 +08:00
github-actions[bot]
1cf4ae3fc3 [Backport release-1.7] Feat: add the updating the application trigger API (#5395)
* Feat: add the updating the application trigger API

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 05bc42bc50)

* Fix: change the test case

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit d6f3e0e90b)

* Fix: imported more than once

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 37f7af0beb)

---------

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2023-01-31 17:14:03 +08:00
qiaozp
444d315143 Fix: rework on apisrever e2e test covergae (#5390)
Signed-off-by: Qiaozp <qiaozhongpei.qzp@alibaba-inc.com>
2023-01-31 15:04:24 +08:00
github-actions[bot]
2e3a89f6b1 Chore: update workflow version to fix panic (#5386)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
(cherry picked from commit 4ae1fe044e)

Co-authored-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2023-01-31 10:57:40 +08:00
github-actions[bot]
d94293ac59 Fix: failed to create the record when rollbacking the application (#5381)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 57d85ecb7c)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2023-01-30 20:51:04 +08:00
github-actions[bot]
cc604cfadb Feat: upgrade cluster gateway to 1.7.0 (#5356)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit 3245ea148c)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
2023-01-19 11:21:38 +08:00
26 changed files with 884 additions and 155 deletions

View File

@@ -186,7 +186,7 @@ jobs:
uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: /tmp/e2e_apiserver_test.out
files: /tmp/e2e-profile.out, /tmp/e2e_apiserver_test.out
flags: apiserver-e2etests
name: codecov-umbrella

View File

@@ -111,7 +111,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0-alpha.3` |
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0` |
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |

View File

@@ -148,7 +148,7 @@ multicluster:
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.7.0-alpha.3
tag: v1.7.0
pullPolicy: IfNotPresent
resources:
limits:

View File

@@ -105,7 +105,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-minimal --
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.4.0` |
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.7.0` |
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |

View File

@@ -106,7 +106,7 @@ multicluster:
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.4.0
tag: v1.7.0
pullPolicy: IfNotPresent
resources:
limits:

View File

@@ -21,6 +21,7 @@ import (
"strconv"
"time"
pkgclient "github.com/kubevela/pkg/controller/client"
ctrlrec "github.com/kubevela/pkg/controller/reconciler"
pkgmulticluster "github.com/kubevela/pkg/multicluster"
wfTypes "github.com/kubevela/workflow/pkg/types"
@@ -171,6 +172,7 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
local := flag.NewFlagSet("klog", flag.ExitOnError)
klog.InitFlags(local)
kfs.AddGoFlagSet(local)
pkgclient.AddTimeoutControllerClientFlags(fss.FlagSet("controllerclient"))
if s.LogDebug {
_ = kfs.Set("v", strconv.Itoa(int(commonconfig.LogDebug)))

View File

@@ -2086,7 +2086,7 @@
"tags": [
"application"
],
"summary": "list application triggers",
"summary": "List the application triggers",
"operationId": "listApplicationTriggers",
"parameters": [
{
@@ -2124,7 +2124,7 @@
"tags": [
"application"
],
"summary": "create one application trigger",
"summary": "Create an application trigger",
"operationId": "createApplicationTrigger",
"parameters": [
{
@@ -2160,6 +2160,51 @@
}
},
"/api/v1/applications/{appName}/triggers/{token}": {
"put": {
"consumes": [
"application/xml",
"application/json"
],
"produces": [
"application/json",
"application/xml"
],
"tags": [
"application"
],
"summary": "Update an application trigger",
"operationId": "updateApplicationTrigger",
"parameters": [
{
"type": "string",
"description": "identifier of the application ",
"name": "appName",
"in": "path",
"required": true
},
{
"type": "string",
"description": "identifier of the trigger",
"name": "token",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ApplicationTriggerBase"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/bcode.Bcode"
}
}
}
},
"delete": {
"consumes": [
"application/xml",
@@ -2172,7 +2217,7 @@
"tags": [
"application"
],
"summary": "delete one application trigger",
"summary": "Delete an application trigger",
"operationId": "deleteApplicationTrigger",
"parameters": [
{
@@ -8964,8 +9009,8 @@
},
"model.ApplicationRevision": {
"required": [
"createTime",
"updateTime",
"createTime",
"appPrimaryKey",
"version",
"revisionCRName",
@@ -9347,11 +9392,11 @@
},
"model.WorkflowStep": {
"required": [
"alias",
"name",
"dependsOn",
"description",
"orderIndex",
"dependsOn",
"name",
"alias",
"type"
],
"properties": {
@@ -9469,9 +9514,9 @@
},
"model.WorkflowStepStatus": {
"required": [
"id",
"name",
"alias"
"alias",
"id"
],
"properties": {
"alias": {
@@ -10055,11 +10100,11 @@
"v1.ApplicationDeployResponse": {
"required": [
"version",
"status",
"triggerType",
"createTime",
"status",
"note",
"envName",
"triggerType",
"record"
],
"properties": {
@@ -10338,6 +10383,7 @@
"type",
"payloadType",
"token",
"registry",
"createTime",
"updateTime"
],
@@ -10361,6 +10407,9 @@
"payloadType": {
"type": "string"
},
"registry": {
"type": "string"
},
"token": {
"type": "string"
},
@@ -10833,13 +10882,13 @@
},
"v1.ConfigTemplateDetail": {
"required": [
"sensitive",
"createTime",
"alias",
"name",
"namespace",
"description",
"scope",
"sensitive",
"createTime",
"alias",
"schema",
"uiSchema"
],
@@ -11669,11 +11718,11 @@
},
"v1.DetailAddonResponse": {
"required": [
"invisible",
"name",
"version",
"description",
"icon",
"invisible",
"description",
"schema",
"uiSchema",
"definitions",
@@ -11753,12 +11802,12 @@
},
"v1.DetailApplicationResponse": {
"required": [
"project",
"createTime",
"updateTime",
"name",
"alias",
"project",
"description",
"createTime",
"updateTime",
"icon",
"policies",
"envBindings",
@@ -11816,20 +11865,20 @@
},
"v1.DetailClusterResponse": {
"required": [
"status",
"provider",
"dashboardURL",
"description",
"icon",
"labels",
"reason",
"apiServerURL",
"kubeConfigSecret",
"alias",
"status",
"dashboardURL",
"icon",
"description",
"reason",
"createTime",
"updateTime",
"name",
"kubeConfig",
"labels",
"provider",
"apiServerURL",
"createTime",
"resourceInfo"
],
"properties": {
@@ -11887,13 +11936,13 @@
},
"v1.DetailComponentResponse": {
"required": [
"name",
"main",
"alias",
"createTime",
"updateTime",
"appPrimaryKey",
"creator",
"name",
"main",
"createTime",
"updateTime",
"alias",
"type",
"definition"
],
@@ -11982,12 +12031,12 @@
},
"v1.DetailDefinitionResponse": {
"required": [
"alias",
"labels",
"ownerAddon",
"name",
"alias",
"icon",
"labels",
"description",
"icon",
"status",
"schema",
"uiSchema"
@@ -12045,15 +12094,15 @@
},
"v1.DetailPolicyResponse": {
"required": [
"description",
"creator",
"envName",
"name",
"alias",
"type",
"description",
"createTime",
"updateTime",
"type",
"properties"
"alias",
"creator",
"properties",
"envName"
],
"properties": {
"alias": {
@@ -12095,18 +12144,18 @@
},
"v1.DetailRevisionResponse": {
"required": [
"appPrimaryKey",
"revisionCRName",
"triggerType",
"workflowName",
"version",
"status",
"deployUser",
"note",
"createTime",
"appPrimaryKey",
"deployUser",
"triggerType",
"updateTime",
"revisionCRName",
"reason",
"envName"
"envName",
"version",
"workflowName",
"createTime"
],
"properties": {
"appPrimaryKey": {
@@ -12163,10 +12212,10 @@
},
"v1.DetailTargetResponse": {
"required": [
"updateTime",
"name",
"project",
"createTime",
"updateTime"
"project"
],
"properties": {
"alias": {
@@ -12206,11 +12255,11 @@
},
"v1.DetailUserResponse": {
"required": [
"email",
"disabled",
"createTime",
"lastLoginTime",
"name",
"email",
"projects",
"roles"
],
@@ -12252,12 +12301,12 @@
"v1.DetailWorkflowRecordResponse": {
"required": [
"status",
"mode",
"workflowAlias",
"applicationRevision",
"namespace",
"message",
"mode",
"name",
"namespace",
"workflowName",
"deployTime",
"deployUser",
@@ -12321,15 +12370,15 @@
"v1.DetailWorkflowResponse": {
"required": [
"name",
"enable",
"envName",
"alias",
"description",
"default",
"createTime",
"updateTime",
"subMode",
"alias",
"enable",
"default",
"envName",
"mode"
"mode",
"subMode"
],
"properties": {
"alias": {
@@ -12537,8 +12586,8 @@
},
"v1.EnvBindingTarget": {
"required": [
"name",
"alias"
"alias",
"name"
],
"properties": {
"alias": {
@@ -12565,11 +12614,11 @@
"v1.GetPipelineResponse": {
"required": [
"spec",
"description",
"createTime",
"name",
"alias",
"project",
"description",
"info"
],
"properties": {
@@ -12612,10 +12661,10 @@
},
"v1.GetPipelineRunLogResponse": {
"required": [
"phase",
"id",
"name",
"type",
"phase",
"source",
"log"
],
@@ -13269,11 +13318,11 @@
},
"v1.LoginUserInfoResponse": {
"required": [
"createTime",
"lastLoginTime",
"name",
"email",
"disabled",
"createTime",
"lastLoginTime",
"projects",
"platformPermissions",
"projectPermissions"
@@ -13475,11 +13524,11 @@
},
"v1.PipelineBase": {
"required": [
"description",
"createTime",
"name",
"alias",
"project",
"description",
"spec"
],
"properties": {
@@ -13578,11 +13627,11 @@
},
"v1.PipelineMetaResponse": {
"required": [
"name",
"alias",
"project",
"description",
"createTime",
"name",
"alias"
"createTime"
],
"properties": {
"alias": {
@@ -13605,13 +13654,13 @@
},
"v1.PipelineRun": {
"required": [
"contextName",
"contextValues",
"spec",
"pipelineName",
"project",
"pipelineRunName",
"record",
"contextName",
"contextValues",
"spec",
"status"
],
"properties": {
@@ -14208,9 +14257,9 @@
},
"v1.SystemInfoResponse": {
"required": [
"loginType",
"platformID",
"enableCollection",
"loginType",
"systemVersion"
],
"properties": {
@@ -14734,14 +14783,14 @@
},
"v1.WorkflowRecord": {
"required": [
"namespace",
"message",
"status",
"mode",
"name",
"namespace",
"workflowName",
"workflowAlias",
"applicationRevision"
"applicationRevision",
"mode",
"message"
],
"properties": {
"applicationRevision": {
@@ -14832,8 +14881,8 @@
},
"v1.WorkflowStep": {
"required": [
"type",
"name"
"name",
"type"
],
"properties": {
"alias": {

2
go.mod
View File

@@ -57,7 +57,7 @@ require (
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51
github.com/kubevela/prism v1.7.0-alpha.1
github.com/kubevela/workflow v0.4.0
github.com/kubevela/workflow v0.4.1
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd

4
go.sum
View File

@@ -1289,8 +1289,8 @@ github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51 h1:xrcNNaAjqC6tr1leSY
github.com/kubevela/pkg v0.0.0-20230105054759-263dc191bf51/go.mod h1:ZRnxY/gOcg/8FilZA+eYr+rtVXb1ijT5HFTe8zrv9zo=
github.com/kubevela/prism v1.7.0-alpha.1 h1:oeZFn1Oy6gxSSFzMTfsWjLOCKaaooMVm1JGNK4j4Mlo=
github.com/kubevela/prism v1.7.0-alpha.1/go.mod h1:AJSDfdA+RkRSnWx3xEcogbmOTpX+l7RSIwqVHxwUtaI=
github.com/kubevela/workflow v0.4.0 h1:Zzb9wPOvLUGEArdnC6EsfNM5j3VNJj0/v2iDKq1JT3k=
github.com/kubevela/workflow v0.4.0/go.mod h1:AX/WL3G/YBkpmNpA/SKKm9M3Y0T9y95gZA8mFWylkyM=
github.com/kubevela/workflow v0.4.1 h1:lYeWE9KgSSkb368u8G7cGfyzCz41Am8MdxgViRFJxXE=
github.com/kubevela/workflow v0.4.1/go.mod h1:AX/WL3G/YBkpmNpA/SKKm9M3Y0T9y95gZA8mFWylkyM=
github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U=
github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4=
github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=

View File

@@ -99,6 +99,7 @@ type ApplicationService interface {
CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
ListApplicationTriggers(ctx context.Context, app *model.Application) ([]*apisv1.ApplicationTriggerBase, error)
DeleteApplicationTrigger(ctx context.Context, app *model.Application, triggerName string) error
UpdateApplicationTrigger(ctx context.Context, app *model.Application, token string, req apisv1.UpdateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
}
type applicationServiceImpl struct {
@@ -410,6 +411,18 @@ func (c *applicationServiceImpl) CreateApplication(ctx context.Context, req apis
// CreateApplicationTrigger create application trigger
func (c *applicationServiceImpl) CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error) {
// checking the workflow
_, err := c.WorkflowService.GetWorkflow(ctx, app, req.WorkflowName)
if err != nil {
return nil, err
}
if req.ComponentName != "" {
_, err := c.GetApplicationComponent(ctx, app, req.ComponentName)
if err != nil {
return nil, err
}
}
trigger := &model.ApplicationTrigger{
AppPrimaryKey: app.Name,
WorkflowName: req.WorkflowName,
@@ -427,18 +440,7 @@ func (c *applicationServiceImpl) CreateApplicationTrigger(ctx context.Context, a
return nil, err
}
return &apisv1.ApplicationTriggerBase{
WorkflowName: req.WorkflowName,
Name: req.Name,
Alias: req.Alias,
Description: req.Description,
Type: req.Type,
PayloadType: req.PayloadType,
Token: trigger.Token,
ComponentName: trigger.ComponentName,
CreateTime: trigger.CreateTime,
UpdateTime: trigger.UpdateTime,
}, nil
return assembler.ConvertTrigger2DTO(*trigger), nil
}
// DeleteApplicationTrigger delete application trigger
@@ -457,6 +459,42 @@ func (c *applicationServiceImpl) DeleteApplicationTrigger(ctx context.Context, a
return nil
}
// UpdateApplicationTrigger update application trigger
func (c *applicationServiceImpl) UpdateApplicationTrigger(ctx context.Context, app *model.Application, token string, req apisv1.UpdateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error) {
trigger := model.ApplicationTrigger{
AppPrimaryKey: app.PrimaryKey(),
Token: token,
}
if err := c.Store.Get(ctx, &trigger); err != nil {
if errors.Is(err, datastore.ErrRecordNotExist) {
return nil, bcode.ErrApplicationTriggerNotExist
}
klog.Warningf("get app trigger failure %s", err.Error())
return nil, err
}
// checking the workflow
_, err := c.WorkflowService.GetWorkflow(ctx, app, req.WorkflowName)
if err != nil {
return nil, err
}
if req.ComponentName != "" {
_, err := c.GetApplicationComponent(ctx, app, req.ComponentName)
if err != nil {
return nil, err
}
}
trigger.Alias = req.Alias
trigger.ComponentName = req.ComponentName
trigger.Description = req.Description
trigger.WorkflowName = req.WorkflowName
trigger.Registry = req.Registry
trigger.PayloadType = req.PayloadType
if err := c.Store.Put(ctx, &trigger); err != nil {
return nil, err
}
return assembler.ConvertTrigger2DTO(trigger), nil
}
// ListApplicationTrigger list application triggers
func (c *applicationServiceImpl) ListApplicationTriggers(ctx context.Context, app *model.Application) ([]*apisv1.ApplicationTriggerBase, error) {
trigger := &model.ApplicationTrigger{
@@ -1715,6 +1753,10 @@ func (c *applicationServiceImpl) RollbackWithRevision(ctx context.Context, appli
if err != nil {
return nil, err
}
// The deploy version is the primary key of the revision
if rollbackApplication.Annotations[oam.AnnotationDeployVersion] == "" {
rollbackApplication.Annotations[oam.AnnotationDeployVersion] = publishVersion
}
record, err := c.WorkflowService.CreateWorkflowRecord(ctx, application, rollbackApplication, &work)
if err != nil {
return nil, fmt.Errorf("create workflow record failure %w", err)

View File

@@ -208,15 +208,17 @@ var _ = Describe("Test application service function", func() {
appModel, err := appService.GetApplication(context.TODO(), testApp)
Expect(err).Should(BeNil())
_, err = appService.CreateApplicationTrigger(context.TODO(), appModel, v1.CreateApplicationTriggerRequest{
Name: "trigger-name",
Name: "trigger-name",
WorkflowName: repository.ConvertWorkflowName("app-dev"),
})
Expect(err).Should(BeNil())
base, err := appService.CreateApplicationTrigger(context.TODO(), appModel, v1.CreateApplicationTriggerRequest{
Name: "trigger-name-2",
ComponentName: "trigger-component",
ComponentName: "component-name",
WorkflowName: repository.ConvertWorkflowName("app-dev"),
})
Expect(err).Should(BeNil())
Expect(base.ComponentName).Should(Equal("trigger-component"))
Expect(base.ComponentName).Should(Equal("component-name"))
})
It("Test ListTriggers function", func() {
@@ -299,6 +301,33 @@ var _ = Describe("Test application service function", func() {
Expect(cmp.Diff(len(detailResponse.Traits), 2)).Should(BeEmpty())
})
It("Test UpdateTrigger function", func() {
appModel, err := appService.GetApplication(context.TODO(), testApp)
Expect(err).Should(BeNil())
triggers, err := appService.ListApplicationTriggers(context.TODO(), appModel)
Expect(err).Should(BeNil())
Expect(len(triggers)).Should(Equal(2))
_, err = appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
ComponentName: "notfound",
WorkflowName: repository.ConvertWorkflowName("app-dev"),
})
Expect(err).Should(Equal(bcode.ErrApplicationComponentNotExist))
_, err = appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
WorkflowName: "notfound",
})
Expect(err).Should(Equal(bcode.ErrWorkflowNotExist))
base, err := appService.UpdateApplicationTrigger(context.TODO(), appModel, triggers[1].Token, v1.UpdateApplicationTriggerRequest{
Alias: triggers[1].Alias,
Description: triggers[1].Description,
ComponentName: "test2",
WorkflowName: repository.ConvertWorkflowName("app-dev"),
PayloadType: triggers[1].PayloadType,
Registry: triggers[1].Registry,
})
Expect(err).Should(BeNil())
Expect(cmp.Diff(base.ComponentName, "test2")).Should(BeEmpty())
})
It("Test DetailComponent function", func() {
appModel, err := appService.GetApplication(context.TODO(), testApp)
Expect(err).Should(BeNil())

View File

@@ -29,6 +29,7 @@ import (
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
"github.com/oam-dev/kubevela/pkg/apiserver/domain/repository"
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
@@ -168,6 +169,7 @@ var _ = Describe("Test application service function", func() {
Name: "test-acr",
PayloadType: "acr",
Type: "webhook",
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
ComponentName: "component-name-webhook",
})
Expect(err).Should(BeNil())
@@ -202,6 +204,7 @@ var _ = Describe("Test application service function", func() {
PayloadType: "acr",
Type: "webhook",
ComponentName: "component-name-webhook",
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
Registry: "test-enterprise-registry.test-region.cr.aliyuncs.com",
})
Expect(err).Should(BeNil())
@@ -236,6 +239,7 @@ var _ = Describe("Test application service function", func() {
PayloadType: "harbor",
Type: "webhook",
ComponentName: "component-name-webhook",
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
})
Expect(err).Should(BeNil())
@@ -274,6 +278,7 @@ var _ = Describe("Test application service function", func() {
PayloadType: "dockerhub",
Type: "webhook",
ComponentName: "component-name-webhook",
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
})
Expect(err).Should(BeNil())
@@ -306,6 +311,7 @@ var _ = Describe("Test application service function", func() {
PayloadType: "jfrog",
Type: "webhook",
ComponentName: "component-name-webhook",
WorkflowName: repository.ConvertWorkflowName("webhook-dev"),
})
Expect(err).Should(BeNil())
jfrogBody := apisv1.HandleApplicationTriggerJFrogRequest{

View File

@@ -48,6 +48,7 @@ var _ = Describe("Test workflow service functions", func() {
projectService *projectServiceImpl
envService *envServiceImpl
envBinding *envBindingServiceImpl
targetService *targetServiceImpl
testProject = "workflow-project"
ds datastore.DataStore
)
@@ -60,6 +61,7 @@ var _ = Describe("Test workflow service functions", func() {
rbacService := &rbacServiceImpl{Store: ds}
projectService = &projectServiceImpl{Store: ds, RbacService: rbacService, K8sClient: k8sClient}
envService = &envServiceImpl{Store: ds, KubeClient: k8sClient, ProjectService: projectService}
targetService = &targetServiceImpl{Store: ds, K8sClient: k8sClient}
envBinding = &envBindingServiceImpl{
Store: ds,
WorkflowService: workflowService,
@@ -77,11 +79,20 @@ var _ = Describe("Test workflow service functions", func() {
ProjectService: projectService,
EnvService: envService,
EnvBindingService: envBinding,
WorkflowService: workflowService,
}
})
It("Test CreateWorkflow function", func() {
_, err := projectService.CreateProject(context.TODO(), apisv1.CreateProjectRequest{Name: testProject})
Expect(err).Should(BeNil())
_, err = targetService.CreateTarget(context.TODO(), apisv1.CreateTargetRequest{
Name: "dev-1", Project: testProject, Cluster: &apisv1.ClusterTarget{ClusterName: "local", Namespace: "dev-1"}})
Expect(err).Should(BeNil())
_, err = envService.CreateEnv(context.TODO(), apisv1.CreateEnvRequest{Name: "dev", Namespace: "dev-1", Targets: []string{"dev-1"}, Project: testProject})
Expect(err).Should(BeNil())
reqApp := apisv1.CreateApplicationRequest{
Name: appName,
Project: testProject,

View File

@@ -118,7 +118,7 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
Writes(apis.ApplicationStatisticsResponse{}))
ws.Route(ws.POST("/{appName}/triggers").To(c.createApplicationTrigger).
Doc("create one application trigger").
Doc("Create an application trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
Filter(c.RbacService.CheckPerm("trigger", "create")).
Filter(c.appCheckFilter).
@@ -129,7 +129,7 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
Writes(apis.ApplicationTriggerBase{}))
ws.Route(ws.DELETE("/{appName}/triggers/{token}").To(c.deleteApplicationTrigger).
Doc("delete one application trigger").
Doc("Delete an application trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
Filter(c.RbacService.CheckPerm("trigger", "delete")).
Filter(c.appCheckFilter).
@@ -139,8 +139,19 @@ func (c *application) GetWebServiceRoute() *restful.WebService {
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]*apis.EmptyResponse{}))
ws.Route(ws.PUT("/{appName}/triggers/{token}").To(c.updateApplicationTrigger).
Doc("Update an application trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
Filter(c.RbacService.CheckPerm("trigger", "update")).
Filter(c.appCheckFilter).
Param(ws.PathParameter("appName", "identifier of the application ").DataType("string")).
Param(ws.PathParameter("token", "identifier of the trigger").DataType("string")).
Returns(200, "OK", apis.ApplicationTriggerBase{}).
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]*apis.ApplicationTriggerBase{}))
ws.Route(ws.GET("/{appName}/triggers").To(c.listApplicationTriggers).
Doc("list application triggers").
Doc("List the application triggers").
Metadata(restfulspec.KeyOpenAPITags, tags).
Filter(c.RbacService.CheckPerm("trigger", "list")).
Filter(c.appCheckFilter).
@@ -747,6 +758,24 @@ func (c *application) deleteApplicationTrigger(req *restful.Request, res *restfu
}
}
func (c *application) updateApplicationTrigger(req *restful.Request, res *restful.Response) {
var updateReq apis.UpdateApplicationTriggerRequest
if err := req.ReadEntity(&updateReq); err != nil {
bcode.ReturnError(req, res, err)
return
}
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
trigger, err := c.ApplicationService.UpdateApplicationTrigger(req.Request.Context(), app, req.PathParameter("token"), updateReq)
if err != nil {
bcode.ReturnError(req, res, err)
return
}
if err := res.WriteEntity(trigger); err != nil {
bcode.ReturnError(req, res, err)
return
}
}
func (c *application) publishApplicationTemplate(req *restful.Request, res *restful.Response) {
app := req.Request.Context().Value(&apis.CtxKeyApplication).(*model.Application)
base, err := c.ApplicationService.PublishApplicationTemplate(req.Request.Context(), app)

View File

@@ -274,6 +274,23 @@ func ConvertPermission2DTO(permission *model.Permission) *apisv1.PermissionBase
}
}
// ConvertTrigger2DTO convert trigger model to the DTO
func ConvertTrigger2DTO(trigger model.ApplicationTrigger) *apisv1.ApplicationTriggerBase {
return &apisv1.ApplicationTriggerBase{
WorkflowName: trigger.WorkflowName,
Name: trigger.Name,
Alias: trigger.Alias,
Description: trigger.Description,
Type: trigger.Type,
PayloadType: trigger.PayloadType,
Token: trigger.Token,
Registry: trigger.Registry,
ComponentName: trigger.ComponentName,
CreateTime: trigger.CreateTime,
UpdateTime: trigger.UpdateTime,
}
}
func convertBool(b *bool) bool {
if b == nil {
return false

View File

@@ -512,6 +512,16 @@ type CreateApplicationTriggerRequest struct {
Registry string `json:"registry,omitempty" optional:"true"`
}
// UpdateApplicationTriggerRequest update application trigger
type UpdateApplicationTriggerRequest struct {
Alias string `json:"alias" validate:"checkalias" optional:"true"`
Description string `json:"description" optional:"true"`
WorkflowName string `json:"workflowName"`
PayloadType string `json:"payloadType" validate:"checkpayloadtype"`
ComponentName string `json:"componentName,omitempty" optional:"true"`
Registry string `json:"registry,omitempty" optional:"true"`
}
// ApplicationTriggerBase application trigger base model
type ApplicationTriggerBase struct {
Name string `json:"name"`
@@ -522,6 +532,7 @@ type ApplicationTriggerBase struct {
PayloadType string `json:"payloadType"`
Token string `json:"token"`
ComponentName string `json:"componentName,omitempty"`
Registry string `json:"registry"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
}

View File

@@ -206,14 +206,37 @@ type Factory interface {
MergeDistributionStatus(ctx context.Context, config *Config, namespace string) error
}
// Dispatcher is a client for apply resources.
type Dispatcher func(context.Context, []*unstructured.Unstructured, []apply.ApplyOption) error
// NewConfigFactory create a config factory instance
func NewConfigFactory(cli client.Client) Factory {
return &kubeConfigFactory{cli: cli, apiApply: apply.NewAPIApplicator(cli)}
return &kubeConfigFactory{cli: cli, apiApply: defaultDispatcher(cli)}
}
// NewConfigFactoryWithDispatcher create a config factory instance with a specified dispatcher
func NewConfigFactoryWithDispatcher(cli client.Client, ds Dispatcher) Factory {
if ds == nil {
ds = defaultDispatcher(cli)
}
return &kubeConfigFactory{cli: cli, apiApply: ds}
}
func defaultDispatcher(cli client.Client) Dispatcher {
api := apply.NewAPIApplicator(cli)
return func(ctx context.Context, manifests []*unstructured.Unstructured, ao []apply.ApplyOption) error {
for _, m := range manifests {
if err := api.Apply(ctx, m, ao...); err != nil {
return err
}
}
return nil
}
}
type kubeConfigFactory struct {
cli client.Client
apiApply *apply.APIApplicator
apiApply Dispatcher
}
// ParseTemplate parse a config template instance form the cue script
@@ -307,7 +330,14 @@ func (k *kubeConfigFactory) CreateOrUpdateConfigTemplate(ctx context.Context, ns
if ns != "" {
it.ConfigMap.Namespace = ns
}
return k.apiApply.Apply(ctx, it.ConfigMap, apply.DisableUpdateAnnotation(), apply.Quiet())
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(it.ConfigMap)
if err != nil {
return fmt.Errorf("fail to convert configmap to unstructured: %w", err)
}
us := &unstructured.Unstructured{Object: obj}
us.SetAPIVersion("v1")
us.SetKind("ConfigMap")
return k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()})
}
func convertConfigMap2Template(cm v1.ConfigMap) (*Template, error) {
@@ -562,11 +592,20 @@ func (k *kubeConfigFactory) CreateOrUpdateConfig(ctx context.Context, i *Config,
return ErrChangeSecretType
}
}
if err := k.apiApply.Apply(ctx, i.Secret, apply.Quiet()); err != nil {
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(i.Secret)
if err != nil {
return fmt.Errorf("fail to convert secret to unstructured: %w", err)
}
us := &unstructured.Unstructured{Object: obj}
us.SetAPIVersion("v1")
us.SetKind("Secret")
if err := k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()}); err != nil {
return fmt.Errorf("fail to apply the secret: %w", err)
}
for key, obj := range i.OutputObjects {
if err := k.apiApply.Apply(ctx, obj, apply.Quiet()); err != nil {
if err := k.apiApply(ctx, []*unstructured.Unstructured{obj}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()}); err != nil {
return fmt.Errorf("fail to apply the object %s: %w", key, err)
}
}
@@ -768,7 +807,15 @@ func (k *kubeConfigFactory) CreateOrUpdateDistribution(ctx context.Context, ns,
Policies: policies,
},
}
return k.apiApply.Apply(ctx, distribution, apply.Quiet())
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(distribution)
if err != nil {
return fmt.Errorf("fail to convert application to unstructured: %w", err)
}
us := &unstructured.Unstructured{Object: obj}
us.SetAPIVersion(v1beta1.SchemeGroupVersion.String())
us.SetKind(v1beta1.ApplicationKind)
return k.apiApply(ctx, []*unstructured.Unstructured{us}, []apply.ApplyOption{apply.DisableUpdateAnnotation(), apply.Quiet()})
}
func (k *kubeConfigFactory) ListDistributions(ctx context.Context, ns string) ([]*Distribution, error) {

View File

@@ -0,0 +1,147 @@
/*
Copyright 2023 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"errors"
"strings"
"sigs.k8s.io/controller-runtime/pkg/client"
monitorContext "github.com/kubevela/pkg/monitor/context"
wfContext "github.com/kubevela/workflow/pkg/context"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/types"
"github.com/oam-dev/kubevela/pkg/config"
)
const (
// ProviderName is provider name
ProviderName = "config"
)
// ErrRequestInvalid means the request is invalid
var ErrRequestInvalid = errors.New("the request is in valid")
type provider struct {
factory config.Factory
}
// CreateConfigProperties the request body for creating a config
type CreateConfigProperties struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Template string `json:"template,omitempty"`
Config map[string]interface{} `json:"config"`
}
// Response the response body
type Response struct {
Status string `json:"status"`
Message string `json:"message"`
}
func (p *provider) Create(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
var ccp CreateConfigProperties
if err := v.UnmarshalTo(&ccp); err != nil {
return ErrRequestInvalid
}
name := ccp.Template
namespace := "vela-system"
if strings.Contains(ccp.Template, "/") {
namespacedName := strings.SplitN(ccp.Template, "/", 2)
namespace = namespacedName[0]
name = namespacedName[1]
}
configItem, err := p.factory.ParseConfig(ctx.GetContext(), config.NamespacedName{
Name: name,
Namespace: namespace,
}, config.Metadata{
NamespacedName: config.NamespacedName{
Name: ccp.Name,
Namespace: ccp.Namespace,
},
Properties: ccp.Config,
})
if err != nil {
return err
}
return p.factory.CreateOrUpdateConfig(ctx.GetContext(), configItem, ccp.Namespace)
}
func (p *provider) Read(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
var nn config.NamespacedName
if err := v.UnmarshalTo(&nn); err != nil {
return ErrRequestInvalid
}
content, err := p.factory.ReadConfig(ctx.GetContext(), nn.Namespace, nn.Name)
if err != nil {
return err
}
return v.FillObject(content, "config")
}
func (p *provider) List(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
template, err := v.GetString("template")
if err != nil {
return ErrRequestInvalid
}
namespace, err := v.GetString("namespace")
if err != nil {
return ErrRequestInvalid
}
if strings.Contains(template, "/") {
namespacedName := strings.SplitN(template, "/", 2)
template = namespacedName[1]
}
configs, err := p.factory.ListConfigs(ctx.GetContext(), namespace, template, "", false)
if err != nil {
return err
}
var contents = []map[string]interface{}{}
for _, config := range configs {
contents = append(contents, map[string]interface{}{
"name": config.Name,
"alias": config.Alias,
"description": config.Description,
"config": config.Properties,
})
}
return v.FillObject(contents, "configs")
}
func (p *provider) Delete(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error {
var nn config.NamespacedName
if err := v.UnmarshalTo(&nn); err != nil {
return errors.New("the request is in valid")
}
return p.factory.DeleteConfig(ctx.GetContext(), nn.Namespace, nn.Name)
}
// Install register handlers to provider discover.
func Install(p types.Providers, cli client.Client, apply config.Dispatcher) {
prd := &provider{
factory: config.NewConfigFactoryWithDispatcher(cli, apply),
}
p.Register(ProviderName, map[string]types.Handler{
"create": prd.Create,
"read": prd.Read,
"list": prd.List,
"delete": prd.Delete,
})
}

View File

@@ -0,0 +1,237 @@
/*
Copyright 2023 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"strings"
"testing"
"time"
monitorContext "github.com/kubevela/pkg/monitor/context"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
wfContext "github.com/kubevela/workflow/pkg/context"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/config"
)
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
var scheme = runtime.NewScheme()
var p *provider
func TestProvider(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Test Config Suite")
}
var _ = BeforeSuite(func(done Done) {
By("Bootstrapping test environment")
testEnv = &envtest.Environment{
ControlPlaneStartTimeout: time.Minute,
ControlPlaneStopTimeout: time.Minute,
UseExistingCluster: pointer.BoolPtr(false),
}
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
Expect(clientgoscheme.AddToScheme(scheme)).Should(BeNil())
// +kubebuilder:scaffold:scheme
By("Create the k8s client")
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
p = &provider{
factory: config.NewConfigFactory(k8sClient),
}
close(done)
}, 120)
var _ = AfterSuite(func() {
By("Tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})
var _ = Describe("Test the config provider", func() {
It("test creating a config", func() {
mCtx := monitorContext.NewTraceContext(context.Background(), "")
v, err := value.NewValue(`
name: "hub-kubevela"
namespace: "default"
template: "default/test-image-registry"
config: {
registry: "hub.kubevela.net"
}
`, nil, "")
Expect(err).ToNot(HaveOccurred())
err = p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)
Expect(strings.Contains(err.Error(), "the template is not exist")).Should(BeTrue())
template, err := p.factory.ParseTemplate("test-image-registry", []byte(templateContent))
Expect(err).ToNot(HaveOccurred())
Expect(p.factory.CreateOrUpdateConfigTemplate(context.TODO(), "default", template)).ToNot(HaveOccurred())
Expect(p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
})
It("test creating a config without the template", func() {
mCtx := monitorContext.NewTraceContext(context.Background(), "")
v, err := value.NewValue(`
name: "www-kubevela"
namespace: "default"
config: {
url: "kubevela.net"
}
`, nil, "")
Expect(err).ToNot(HaveOccurred())
Expect(p.Create(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
})
It("test listing the config", func() {
mCtx := monitorContext.NewTraceContext(context.Background(), "")
v, err := value.NewValue(`
namespace: "default"
template: "test-image-registry"
`, nil, "")
Expect(err).ToNot(HaveOccurred())
Expect(p.List(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
configs, err := v.LookupValue("configs")
Expect(err).ToNot(HaveOccurred())
var contents []map[string]interface{}
Expect(configs.UnmarshalTo(&contents)).ToNot(HaveOccurred())
Expect(len(contents)).To(Equal(1))
Expect(contents[0]["config"].(map[string]interface{})["registry"]).To(Equal("hub.kubevela.net"))
})
It("test reading the config", func() {
mCtx := monitorContext.NewTraceContext(context.Background(), "")
v, err := value.NewValue(`
name: "hub-kubevela"
namespace: "default"
`, nil, "")
Expect(err).ToNot(HaveOccurred())
Expect(p.Read(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
registry, err := v.GetString("config", "registry")
Expect(err).ToNot(HaveOccurred())
Expect(registry).To(Equal("hub.kubevela.net"))
})
It("test deleting the config", func() {
mCtx := monitorContext.NewTraceContext(context.Background(), "")
v, err := value.NewValue(`
name: "hub-kubevela"
namespace: "default"
`, nil, "")
Expect(err).ToNot(HaveOccurred())
Expect(p.Delete(mCtx, new(wfContext.WorkflowContext), v, nil)).ToNot(HaveOccurred())
configs, err := p.factory.ListConfigs(context.Background(), "default", "", "", false)
Expect(err).ToNot(HaveOccurred())
Expect(len(configs)).To(Equal(1))
Expect(configs[0].Properties["url"]).To(Equal("kubevela.net"))
})
})
var templateContent = `
import (
"encoding/base64"
"encoding/json"
"strconv"
)
metadata: {
name: "image-registry"
alias: "Image Registry"
scope: "project"
description: "Config information to authenticate image registry"
sensitive: false
}
template: {
output: {
apiVersion: "v1"
kind: "Secret"
metadata: {
name: context.name
namespace: context.namespace
labels: {
"config.oam.dev/catalog": "velacore-config"
"config.oam.dev/type": "image-registry"
}
}
if parameter.auth != _|_ {
type: "kubernetes.io/dockerconfigjson"
}
if parameter.auth == _|_ {
type: "Opaque"
}
stringData: {
if parameter.auth != _|_ && parameter.auth.username != _|_ {
".dockerconfigjson": json.Marshal({
"auths": (parameter.registry): {
"username": parameter.auth.username
"password": parameter.auth.password
if parameter.auth.email != _|_ {
"email": parameter.auth.email
}
"auth": base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
}
})
}
if parameter.insecure != _|_ {
"insecure-skip-verify": strconv.FormatBool(parameter.insecure)
}
if parameter.useHTTP != _|_ {
"protocol-use-http": strconv.FormatBool(parameter.useHTTP)
}
}
}
parameter: {
// +usage=Image registry FQDN, such as: index.docker.io
registry: *"index.docker.io" | string
// +usage=Authenticate the image registry
auth?: {
// +usage=Private Image registry username
username: string
// +usage=Private Image registry password
password: string
// +usage=Private Image registry email
email?: string
}
// +usage=For the registry server that uses the self-signed certificate
insecure?: bool
// +usage=For the registry server that uses the HTTP protocol
useHTTP?: bool
}
}
`

View File

@@ -25,7 +25,9 @@ import (
pkgmulticluster "github.com/kubevela/pkg/multicluster"
utilfeature "k8s.io/apiserver/pkg/util/feature"
configprovider "github.com/oam-dev/kubevela/pkg/config/provider"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/pkg/errors"
@@ -86,15 +88,21 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
af *appfile.Appfile,
appRev *v1beta1.ApplicationRevision) (*wfTypes.WorkflowInstance, []wfTypes.TaskRunner, error) {
appLabels := map[string]string{
oam.LabelAppName: app.Name,
oam.LabelAppNamespace: app.Namespace,
}
handlerProviders := providers.NewProviders()
kube.Install(handlerProviders, h.r.Client,
map[string]string{
oam.LabelAppName: app.Name,
oam.LabelAppNamespace: app.Namespace,
}, &kube.Handlers{
Apply: h.Dispatch,
Delete: h.Delete,
})
kube.Install(handlerProviders, h.r.Client, appLabels, &kube.Handlers{
Apply: h.Dispatch,
Delete: h.Delete,
})
configprovider.Install(handlerProviders, h.r.Client, func(ctx context.Context, resources []*unstructured.Unstructured, applyOptions []apply.ApplyOption) error {
for _, res := range resources {
res.SetLabels(util.MergeMapOverrideWithDst(res.GetLabels(), appLabels))
}
return h.resourceKeeper.Dispatch(ctx, resources, applyOptions)
})
oamProvider.Install(handlerProviders, app, af, h.r.Client, h.applyComponentFunc(
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
pCtx := velaprocess.NewContext(generateContextDataFromApp(app, appRev.Name))

View File

@@ -121,8 +121,8 @@ func loggingApply(msg string, desired client.Object, quiet bool) {
klog.InfoS(msg, "name", d.GetName(), "resource", desired.GetObjectKind().GroupVersionKind().String())
}
// filterRecordForSpecial will filter special object that can reduce the record for "app.oam.dev/last-applied-configuration" annotation.
func filterRecordForSpecial(desired client.Object) bool {
// trimLastAppliedConfigurationForSpecialResources will filter special object that can reduce the record for "app.oam.dev/last-applied-configuration" annotation.
func trimLastAppliedConfigurationForSpecialResources(desired client.Object) bool {
if desired == nil {
return false
}
@@ -159,7 +159,7 @@ func (a *APIApplicator) Apply(ctx context.Context, desired client.Object, ao ...
if err != nil {
return err
}
applyAct := &applyAction{updateAnnotation: filterRecordForSpecial(desired)}
applyAct := &applyAction{updateAnnotation: trimLastAppliedConfigurationForSpecialResources(desired)}
existing, err := a.createOrGetExisting(ctx, applyAct, a.c, desired, ao...)
if err != nil {
return err

View File

@@ -574,15 +574,15 @@ func TestFilterSpecialAnn(t *testing.T) {
var sc = &corev1.Secret{}
var dp = &appsv1.Deployment{}
var crd = &v1.CustomResourceDefinition{}
assert.Equal(t, false, filterRecordForSpecial(cm))
assert.Equal(t, false, filterRecordForSpecial(sc))
assert.Equal(t, false, filterRecordForSpecial(crd))
assert.Equal(t, true, filterRecordForSpecial(dp))
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(cm))
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(sc))
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(crd))
assert.Equal(t, true, trimLastAppliedConfigurationForSpecialResources(dp))
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "-"}
assert.Equal(t, false, filterRecordForSpecial(dp))
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(dp))
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "skip"}
assert.Equal(t, false, filterRecordForSpecial(dp))
assert.Equal(t, false, trimLastAppliedConfigurationForSpecialResources(dp))
dp.Annotations = map[string]string{oam.AnnotationLastAppliedConfig: "xxx"}
assert.Equal(t, true, filterRecordForSpecial(dp))
assert.Equal(t, true, trimLastAppliedConfigurationForSpecialResources(dp))
}

View File

@@ -52,6 +52,7 @@ import (
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/utils/env"
"github.com/oam-dev/kubevela/pkg/utils/util"
)
@@ -133,6 +134,9 @@ func (opt *AdoptOptions) parseResourceRef(f velacmd.Factory, cmd *cobra.Command,
or.Name = parts[1]
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
or.Namespace = velacmd.GetNamespace(f, cmd)
if or.Namespace == "" {
or.Namespace = env.DefaultEnvNamespace
}
}
case 3:
or.Namespace = parts[1]
@@ -160,6 +164,9 @@ func (opt *AdoptOptions) Complete(f velacmd.Factory, cmd *cobra.Command, args []
}) {
opt.AppName = opt.NativeResourceRefs[0].Name
}
if opt.AppNamespace == "" {
opt.AppNamespace = opt.NativeResourceRefs[0].Namespace
}
case adoptTypeHelm:
if len(args) > 0 {
opt.HelmReleaseName = args[0]

View File

@@ -0,0 +1,58 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/controller-runtime/pkg/client/config"
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
"github.com/oam-dev/kubevela/pkg/utils/util"
)
func TestDefaultNamespace(t *testing.T) {
testcase := []struct {
namespace string
args []string
}{
{
namespace: "kube-system",
args: []string{"deployment/kube-system/metrics-server"},
},
{
namespace: "default",
args: []string{"deployment/metrics-server"},
},
}
for _, c := range testcase {
opt := &AdoptOptions{
Type: adoptTypeNative,
Mode: adoptModeReadOnly,
}
f := velacmd.NewDeferredFactory(config.GetConfig)
ioStream := util.IOStreams{}
cmd := NewAdoptCommand(f, ioStream)
err := opt.Complete(f, cmd, c.args)
if err != nil {
t.Fatalf("failed to parse resourceRef: %v", err)
}
assert.Equal(t, opt.AppNamespace, c.namespace)
}
}

View File

@@ -307,7 +307,7 @@ func (opt *DeleteOptions) Run(f velacmd.Factory, cmd *cobra.Command) error {
app := &v1beta1.Application{}
if err := f.Client().Get(cmd.Context(), apitypes.NamespacedName{Namespace: opt.Namespace, Name: appName}, app); err != nil {
if kerrors.IsNotFound(err) {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "application %s/%s already deleted", opt.Namespace, appName)
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "application %s/%s already deleted\n", opt.Namespace, appName)
return nil
}
return fmt.Errorf("failed to get application %s/%s: %w", opt.Namespace, appName, err)

View File

@@ -34,9 +34,33 @@ import (
var appName = "app-e2e"
var appProject = "test-app-project"
func prepareEnv(envName string) {
var targetName = testNSprefix + strconv.FormatInt(time.Now().UnixNano(), 10)
// create target
var createTarget = apisv1.CreateTargetRequest{
Name: targetName,
Project: appProject,
Cluster: &apisv1.ClusterTarget{
ClusterName: "local",
Namespace: targetName,
},
}
res := post("/targets", createTarget)
Expect(decodeResponseBody(res, nil)).Should(Succeed())
// create env
var createEnvReq = apisv1.CreateEnvRequest{
Name: envName,
Targets: []string{targetName},
}
res = post("/envs", createEnvReq)
Expect(decodeResponseBody(res, nil)).Should(Succeed())
}
var _ = Describe("Test application rest api", func() {
It("Test create app", func() {
defer GinkgoRecover()
prepareEnv("dev-env")
var req = apisv1.CreateApplicationRequest{
Name: appName,
Project: appProject,
@@ -58,7 +82,7 @@ var _ = Describe("Test application rest api", func() {
Expect(cmp.Diff(appBase.Labels["test"], req.Labels["test"])).Should(BeEmpty())
})
It("Test list components", func() {
It("Test listing components", func() {
defer GinkgoRecover()
res := get("/applications/" + appName + "/components")
var components apisv1.ComponentListResponse
@@ -66,37 +90,42 @@ var _ = Describe("Test application rest api", func() {
Expect(cmp.Diff(len(components.Components), 1)).Should(BeEmpty())
})
It("Test updating a trigger", func() {
defer GinkgoRecover()
res := get("/applications/" + appName + "/triggers")
var triggers apisv1.ListApplicationTriggerResponse
Expect(decodeResponseBody(res, &triggers)).Should(Succeed())
Expect(cmp.Diff(len(triggers.Triggers), 1)).Should(BeEmpty())
old := triggers.Triggers[0]
var req = apisv1.UpdateApplicationTriggerRequest{
Alias: "Update",
Description: "Update the description",
WorkflowName: old.WorkflowName,
PayloadType: old.PayloadType,
ComponentName: old.ComponentName,
Registry: old.Registry,
}
res = put("/applications/"+appName+"/triggers/"+old.Token, req)
var base apisv1.ApplicationTriggerBase
Expect(decodeResponseBody(res, &base)).Should(Succeed())
Expect(cmp.Diff(base.Alias, req.Alias)).Should(BeEmpty())
Expect(cmp.Diff(base.Description, req.Description)).Should(BeEmpty())
})
It("Test detail application", func() {
defer GinkgoRecover()
res := get("/applications/" + appName)
var detail apisv1.DetailApplicationResponse
Expect(decodeResponseBody(res, &detail)).Should(Succeed())
Expect(cmp.Diff(len(detail.Policies), 0)).Should(BeEmpty())
// The policy for the dev-env environment
Expect(cmp.Diff(len(detail.Policies), 1)).Should(BeEmpty())
})
It("Test deploy application", func() {
defer GinkgoRecover()
var targetName = testNSprefix + strconv.FormatInt(time.Now().UnixNano(), 10)
var envName = "dev"
// create target
var createTarget = apisv1.CreateTargetRequest{
Name: targetName,
Project: appProject,
Cluster: &apisv1.ClusterTarget{
ClusterName: "local",
Namespace: targetName,
},
}
res := post("/targets", createTarget)
Expect(decodeResponseBody(res, nil)).Should(Succeed())
// create env
var createEnvReq = apisv1.CreateEnvRequest{
Name: envName,
Targets: []string{targetName},
}
res = post("/envs", createEnvReq)
Expect(decodeResponseBody(res, nil)).Should(Succeed())
prepareEnv(envName)
// create envbinding
var createEnvbindingReq = apisv1.CreateApplicationEnvbindingRequest{
@@ -104,7 +133,7 @@ var _ = Describe("Test application rest api", func() {
Name: envName,
},
}
res = post("/applications/"+appName+"/envs", createEnvbindingReq)
res := post("/applications/"+appName+"/envs", createEnvbindingReq)
Expect(decodeResponseBody(res, nil)).Should(Succeed())
// deploy app