Compare commits

..

7 Commits

Author SHA1 Message Date
barnettZQG
ad4b44696a Feat: add the project api (#2899)
* Feat: add the project api

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

* Fix: fix e2e test bug

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-08 19:08:35 +08:00
barnettZQG
1563c582bc Feat: support additional properties parameter (#2880)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-08 17:46:45 +08:00
Jian.Li
3f2e76c75a Feat: HTTP Provider requires adding certificate chain from secret (#2771)
* http support load tls certs

* fix: TLS MinVersion too low
2021-12-08 11:39:04 +08:00
wyike
f7ebbf4fa0 Fix: create vela namespace (#2893)
Signed-off-by: wangyike <wangyike_wyk@163.com>
2021-12-08 09:12:37 +08:00
Somefive
330c3e269c Fix: kubeconfig tmp file security (#2894)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-08 09:12:07 +08:00
Snyk bot
41e6a895a1 fix: hack/website/Dockerfile to reduce vulnerabilities (#2857)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-DEBIAN9-CURL-1585151
- https://snyk.io/vuln/SNYK-DEBIAN9-GLIBC-356851
- https://snyk.io/vuln/SNYK-DEBIAN9-GLIBC-356851
- https://snyk.io/vuln/SNYK-DEBIAN9-GLIBC-356851
- https://snyk.io/vuln/SNYK-DEBIAN9-GLIBC-356851

Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2021-12-07 18:07:19 +08:00
Jianbo Sun
e8f2b79721 Fix: use specific cli release download folder (#2889)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2021-12-07 17:53:04 +08:00
45 changed files with 1697 additions and 704 deletions

View File

@@ -105,7 +105,7 @@ jobs:
path: ./_bin/sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt
retention-days: 1
upload-sha256sums-plugin-homebrew:
upload-plugin-homebrew:
needs: build
runs-on: ubuntu-latest
name: upload-sha256sums
@@ -119,7 +119,12 @@ jobs:
uses: actions/download-artifact@v2
with:
name: sha256sums
path: cli-artifacts
- name: Display structure of downloaded files
run: ls -R
working-directory: cli-artifacts
- shell: bash
working-directory: cli-artifacts
run: |
for file in *
do
@@ -129,7 +134,7 @@ jobs:
uses: actions/upload-release-asset@v1.0.2
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: sha256sums.txt
asset_path: cli-artifacts/sha256sums.txt
asset_name: sha256sums.txt
asset_content_type: text/plain
- name: Update kubectl plugin version in krew-index

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
FROM node:14.17
FROM node:16.9.0
WORKDIR /workspace
COPY website-dev.sh /workspace

View File

@@ -32,6 +32,7 @@ type Application struct {
Model
Name string `json:"name"`
Alias string `json:"alias"`
Project string `json:"project"`
Namespace string `json:"namespace"`
Description string `json:"description"`
Icon string `json:"icon"`
@@ -57,6 +58,9 @@ func (a *Application) Index() map[string]string {
if a.Namespace != "" {
index["namespace"] = a.Namespace
}
if a.Project != "" {
index["project"] = a.Project
}
return index
}

View File

@@ -25,6 +25,7 @@ func init() {
type DeliveryTarget struct {
Model
Name string `json:"name"`
Project string `json:"project"`
Namespace string `json:"namespace"`
Alias string `json:"alias,omitempty"`
Description string `json:"description,omitempty"`
@@ -51,6 +52,9 @@ func (d *DeliveryTarget) Index() map[string]string {
if d.Namespace != "" {
index["namespace"] = d.Namespace
}
if d.Project != "" {
index["project"] = d.Project
}
return index
}

View File

@@ -0,0 +1,53 @@
/*
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 model
func init() {
RegistModel(&Project{})
}
// Project project model
type Project struct {
Model
Name string `json:"name"`
Alias string `json:"alias"`
Description string `json:"description,omitempty"`
// Namespace Control cluster namespace
Namespace string `json:"namespace"`
}
// TableName return custom table name
func (p *Project) TableName() string {
return tableNamePrefix + "project"
}
// PrimaryKey return custom primary key
func (p *Project) PrimaryKey() string {
return p.Name
}
// Index return custom index
func (p *Project) Index() map[string]string {
index := make(map[string]string)
if p.Name != "" {
index["name"] = p.Name
}
if p.Namespace != "" {
index["namespace"] = p.Namespace
}
return index
}

View File

@@ -58,6 +58,12 @@ const (
// EmptyResponse empty response, it will used for delete api
type EmptyResponse struct{}
// NameAlias name and alias
type NameAlias struct {
Name string `json:"name"`
Alias string `json:"alias"`
}
// CreateAddonRegistryRequest defines the format for addon registry create request
type CreateAddonRegistryRequest struct {
Name string `json:"name" validate:"checkname"`
@@ -253,7 +259,7 @@ type ClusterBase struct {
// ListApplicatioOptions list application query options
type ListApplicatioOptions struct {
Namespace string `json:"namespace"`
Project string `json:"project"`
TargetName string `json:"targetName"`
Query string `json:"query"`
}
@@ -280,7 +286,7 @@ func (e EnvBindingList) ContainTarget(name string) bool {
type ApplicationBase struct {
Name string `json:"name"`
Alias string `json:"alias"`
Namespace string `json:"namespace"`
Project *ProjectBase `json:"project"`
Description string `json:"description"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
@@ -306,7 +312,7 @@ type ApplicationStatisticsResponse struct {
type CreateApplicationRequest struct {
Name string `json:"name" validate:"checkname"`
Alias string `json:"alias" validate:"checkalias" optional:"true"`
Namespace string `json:"namespace" validate:"checkname"`
Project string `json:"project" validate:"checkname"`
Description string `json:"description" optional:"true"`
Icon string `json:"icon"`
Labels map[string]string `json:"labels,omitempty"`
@@ -334,15 +340,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"`
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"`
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 []NameAlias `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
@@ -456,28 +462,26 @@ type ApplicationTemplateVersion struct {
UpdateTime time.Time `json:"updateTime"`
}
// ListNamespaceResponse namesace list model
type ListNamespaceResponse struct {
Namespaces []NamespaceBase `json:"namespaces"`
// ListProjectResponse list project response body
type ListProjectResponse struct {
Projects []*ProjectBase `json:"projects"`
}
// NamespaceBase namespace base model
type NamespaceBase struct {
// ProjectBase project base model
type ProjectBase struct {
Name string `json:"name"`
Alias string `json:"alias"`
Description string `json:"description"`
Namespace string `json:"namespace"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
}
// CreateNamespaceRequest create namespace request body
type CreateNamespaceRequest struct {
// CreateProjectRequest create project request body
type CreateProjectRequest struct {
Name string `json:"name" validate:"checkname"`
Description string `json:"description"`
}
// NamespaceDetailResponse namespace detail response
type NamespaceDetailResponse struct {
NamespaceBase
Alias string `json:"alias" validate:"checkalias" optional:"true"`
Description string `json:"description" optional:"true"`
}
// ListDefinitionResponse list definition response model
@@ -705,7 +709,7 @@ type ApplicationTrait struct {
// CreateDeliveryTargetRequest create delivery target request body
type CreateDeliveryTargetRequest struct {
Name string `json:"name" validate:"checkname"`
Namespace string `json:"namespace" validate:"checkname"`
Project string `json:"project" validate:"checkname"`
Alias string `json:"alias,omitempty" validate:"checkalias" optional:"true"`
Description string `json:"description,omitempty" optional:"true"`
Cluster *ClusterTarget `json:"cluster,omitempty"`
@@ -731,16 +735,16 @@ type DetailDeliveryTargetResponse struct {
DeliveryTargetBase
}
// ListDeliveryTargetResponse list delivery target response body
type ListDeliveryTargetResponse struct {
DeliveryTargets []DeliveryTargetBase `json:"deliveryTargets"`
Total int64 `json:"total"`
// ListTargetResponse list delivery target response body
type ListTargetResponse struct {
Targets []DeliveryTargetBase `json:"targets"`
Total int64 `json:"total"`
}
// DeliveryTargetBase deliveryTarget base model
type DeliveryTargetBase struct {
Name string `json:"name" validate:"checkname"`
Namespace string `json:"namespace" validate:"checkname"`
Name string `json:"name"`
Project *ProjectBase `json:"project"`
Alias string `json:"alias,omitempty" validate:"checkalias" optional:"true"`
Description string `json:"description,omitempty" optional:"true"`
Cluster *ClusterTarget `json:"cluster,omitempty"`

View File

@@ -97,10 +97,17 @@ type applicationUsecaseImpl struct {
envBindingUsecase EnvBindingUsecase
deliveryTargetUsecase DeliveryTargetUsecase
definitionUsecase DefinitionUsecase
projectUsecase ProjectUsecase
}
// NewApplicationUsecase new application usecase
func NewApplicationUsecase(ds datastore.DataStore, workflowUsecase WorkflowUsecase, envBindingUsecase EnvBindingUsecase, deliveryTargetUsecase DeliveryTargetUsecase, definitionUsecase DefinitionUsecase) ApplicationUsecase {
func NewApplicationUsecase(ds datastore.DataStore,
workflowUsecase WorkflowUsecase,
envBindingUsecase EnvBindingUsecase,
deliveryTargetUsecase DeliveryTargetUsecase,
definitionUsecase DefinitionUsecase,
projectUsecase ProjectUsecase,
) ApplicationUsecase {
kubecli, err := clients.GetKubeClient()
if err != nil {
log.Logger.Fatalf("get kubeclient failure %s", err.Error())
@@ -113,14 +120,15 @@ func NewApplicationUsecase(ds datastore.DataStore, workflowUsecase WorkflowUseca
kubeClient: kubecli,
apply: apply.NewAPIApplicator(kubecli),
definitionUsecase: definitionUsecase,
projectUsecase: projectUsecase,
}
}
// ListApplications list applications
func (c *applicationUsecaseImpl) ListApplications(ctx context.Context, listOptions apisv1.ListApplicatioOptions) ([]*apisv1.ApplicationBase, error) {
var app = model.Application{}
if listOptions.Namespace != "" {
app.Namespace = listOptions.Namespace
if listOptions.Project != "" {
app.Project = listOptions.Project
}
entitys, err := c.ds.List(ctx, &app, &datastore.ListOptions{})
if err != nil {
@@ -129,7 +137,7 @@ func (c *applicationUsecaseImpl) ListApplications(ctx context.Context, listOptio
var list []*apisv1.ApplicationBase
for _, entity := range entitys {
appModel := entity.(*model.Application)
appBase := c.converAppModelToBase(appModel)
appBase := c.converAppModelToBase(ctx, appModel)
if listOptions.Query != "" &&
!(strings.Contains(appBase.Alias, listOptions.Query) ||
strings.Contains(appBase.Name, listOptions.Query) ||
@@ -166,7 +174,7 @@ func (c *applicationUsecaseImpl) GetApplication(ctx context.Context, appName str
// DetailApplication detail application info
func (c *applicationUsecaseImpl) DetailApplication(ctx context.Context, app *model.Application) (*apisv1.DetailApplicationResponse, error) {
base := c.converAppModelToBase(app)
base := c.converAppModelToBase(ctx, app)
policys, err := c.queryApplicationPolicys(ctx, app)
if err != nil {
return nil, err
@@ -255,19 +263,27 @@ func (c *applicationUsecaseImpl) CreateApplication(ctx context.Context, req apis
Name: req.Name,
Alias: req.Alias,
Description: req.Description,
Namespace: req.Namespace,
Icon: req.Icon,
Labels: req.Labels,
}
// check app name.
exit, err := c.ds.IsExist(ctx, &application)
exist, err := c.ds.IsExist(ctx, &application)
if err != nil {
log.Logger.Errorf("check application name is exist failure %s", err.Error())
return nil, bcode.ErrApplicationExist
}
if exit {
if exist {
return nil, bcode.ErrApplicationExist
}
// check project
project, err := c.projectUsecase.GetProject(ctx, req.Project)
if err != nil {
return nil, err
}
application.Namespace = project.Namespace
application.Project = project.Name
if req.YamlConfig != "" {
var oamApp v1beta1.Application
if err := yaml.Unmarshal([]byte(req.YamlConfig), &oamApp); err != nil {
@@ -310,7 +326,7 @@ func (c *applicationUsecaseImpl) CreateApplication(ctx context.Context, req apis
return nil, err
}
// render app base info.
base := c.converAppModelToBase(&application)
base := c.converAppModelToBase(ctx, &application)
return base, nil
}
@@ -355,7 +371,7 @@ func (c *applicationUsecaseImpl) UpdateApplication(ctx context.Context, app *mod
if err := c.ds.Put(ctx, app); err != nil {
return nil, err
}
return c.converAppModelToBase(app), nil
return c.converAppModelToBase(ctx, app), nil
}
func (c *applicationUsecaseImpl) saveApplicationComponent(ctx context.Context, app *model.Application, components []common.ApplicationComponent) error {
@@ -831,17 +847,23 @@ func (c *applicationUsecaseImpl) renderOAMApplication(ctx context.Context, appMo
return app, nil
}
func (c *applicationUsecaseImpl) converAppModelToBase(app *model.Application) *apisv1.ApplicationBase {
func (c *applicationUsecaseImpl) converAppModelToBase(ctx context.Context, app *model.Application) *apisv1.ApplicationBase {
appBase := &apisv1.ApplicationBase{
Name: app.Name,
Alias: app.Alias,
Namespace: app.Namespace,
CreateTime: app.CreateTime,
UpdateTime: app.UpdateTime,
Description: app.Description,
Icon: app.Icon,
Labels: app.Labels,
}
project, err := c.projectUsecase.GetProject(ctx, app.Project)
if err != nil {
log.Logger.Errorf("query project info failure %s", err.Error())
}
if project != nil {
appBase.Project = convertProjectModel2Base(project)
}
return appBase
}

View File

@@ -50,12 +50,16 @@ var _ = Describe("Test application usecase function", func() {
envBindingUsecase *envBindingUsecaseImpl
deliveryTargetUsecase *deliveryTargetUsecaseImpl
definitionUsecase *definitionUsecaseImpl
projectUsecase *projectUsecaseImpl
testProject = "app-project"
)
BeforeEach(func() {
workflowUsecase = &workflowUsecaseImpl{ds: ds}
definitionUsecase = &definitionUsecaseImpl{kubeClient: k8sClient}
envBindingUsecase = &envBindingUsecaseImpl{ds: ds, workflowUsecase: workflowUsecase, kubeClient: k8sClient, definitionUsecase: definitionUsecase}
deliveryTargetUsecase = &deliveryTargetUsecaseImpl{ds: ds}
projectUsecase = &projectUsecaseImpl{ds: ds, kubeClient: k8sClient}
appUsecase = &applicationUsecaseImpl{
ds: ds,
workflowUsecase: workflowUsecase,
@@ -64,13 +68,17 @@ var _ = Describe("Test application usecase function", func() {
envBindingUsecase: envBindingUsecase,
definitionUsecase: definitionUsecase,
deliveryTargetUsecase: deliveryTargetUsecase,
projectUsecase: projectUsecase,
}
})
It("Test CreateApplication function", func() {
By("test sample create")
_, err := projectUsecase.CreateProject(context.TODO(), v1.CreateProjectRequest{Name: testProject})
Expect(err).Should(BeNil())
req := v1.CreateApplicationRequest{
Name: "test-app",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app",
EnvBinding: []*v1.EnvBinding{{
Name: "dev",
@@ -95,7 +103,7 @@ var _ = Describe("Test application usecase function", func() {
Expect(err).Should(Succeed())
req = v1.CreateApplicationRequest{
Name: "test-app-sadasd",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -107,7 +115,7 @@ var _ = Describe("Test application usecase function", func() {
req = v1.CreateApplicationRequest{
Name: "test-app-sadasd2",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -122,7 +130,7 @@ var _ = Describe("Test application usecase function", func() {
Expect(err).Should(Succeed())
req = v1.CreateApplicationRequest{
Name: "test-app-sadasd3",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -135,7 +143,7 @@ var _ = Describe("Test application usecase function", func() {
By("Test create app with env binding")
req = v1.CreateApplicationRequest{
Name: "test-app-sadasd4",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -159,7 +167,7 @@ var _ = Describe("Test application usecase function", func() {
appModel, err := appUsecase.GetApplication(context.TODO(), "test-app-sadasd4")
Expect(err).Should(BeNil())
Expect(cmp.Diff(appModel.Namespace, "test-app-namespace")).Should(BeEmpty())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
})
@@ -170,7 +178,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test ListApplications and filter by targetName function", func() {
list, err := appUsecase.ListApplications(context.TODO(), v1.ListApplicatioOptions{
Namespace: "test-app-namespace",
Project: testProject,
TargetName: "dev-target"})
Expect(err).Should(BeNil())
Expect(cmp.Diff(len(list), 2)).Should(BeEmpty())
@@ -179,7 +187,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test DetailApplication 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
detail, err := appUsecase.DetailApplication(context.TODO(), appModel)
Expect(err).Should(BeNil())
@@ -190,7 +198,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test ListComponents 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
components, err := appUsecase.ListComponents(context.TODO(), appModel, v1.ListApplicationComponentOptions{})
Expect(err).Should(BeNil())
@@ -216,7 +224,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test DetailComponent 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
detail, err := appUsecase.DetailComponent(context.TODO(), appModel, "hello-world-server")
Expect(err).Should(BeNil())
@@ -228,7 +236,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test AddComponent 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
base, err := appUsecase.AddComponent(context.TODO(), appModel, v1.CreateComponentRequest{
Name: "test2",
Description: "this is a test2 component",
@@ -244,7 +252,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test DetailComponent 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
detailResponse, err := appUsecase.DetailComponent(context.TODO(), appModel, "test2")
Expect(err).Should(BeNil())
Expect(cmp.Diff(detailResponse.DependsOn[0], "data-worker")).Should(BeEmpty())
@@ -255,7 +263,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test AddPolicy 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
_, err = appUsecase.AddPolicy(context.TODO(), appModel, v1.CreatePolicyRequest{
Name: EnvBindingPolicyDefaultName,
Description: "this is a test2 policy",
@@ -276,7 +284,7 @@ var _ = Describe("Test application usecase function", func() {
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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
policies, err := appUsecase.ListPolicies(context.TODO(), appModel)
Expect(err).Should(BeNil())
@@ -286,7 +294,7 @@ var _ = Describe("Test application usecase function", func() {
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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
detail, err := appUsecase.DetailPolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName)
Expect(err).Should(BeNil())
Expect(detail.Properties).ShouldNot(BeNil())
@@ -296,7 +304,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test UpdatePolicy 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
base, err := appUsecase.UpdatePolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName, v1.UpdatePolicyRequest{
Type: "env-binding",
Properties: `{"envs":{}}`,
@@ -308,7 +316,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test DeletePolicy 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
err = appUsecase.DeletePolicy(context.TODO(), appModel, EnvBindingPolicyDefaultName)
Expect(err).Should(BeNil())
})
@@ -389,7 +397,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test DeleteComponent 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())
Expect(cmp.Diff(appModel.Project, testProject)).Should(BeEmpty())
err = appUsecase.DeleteComponent(context.TODO(), appModel, "test2")
Expect(err).Should(BeNil())
})
@@ -454,7 +462,7 @@ var _ = Describe("Test application usecase function", func() {
It("Test ApplicationEnvRecycle function", func() {
req := v1.CreateApplicationRequest{
Name: "app-env-recycle" + "-dev",
Namespace: "test-app-namespace",
Project: testProject,
Description: "this is a test app with env",
}
base, err := appUsecase.CreateApplication(context.TODO(), req)
@@ -463,7 +471,7 @@ var _ = Describe("Test application usecase function", func() {
err = envBindingUsecase.ApplicationEnvRecycle(context.TODO(), &model.Application{
Name: "app-env-recycle",
Namespace: "test-app-namespace",
Namespace: "project-" + testProject,
}, &model.EnvBinding{Name: "dev"})
Expect(err).Should(BeNil())
})

View File

@@ -184,7 +184,7 @@ func (c *clusterUsecaseImpl) ListKubeClusters(ctx context.Context, query string,
}
func joinClusterByKubeConfigString(ctx context.Context, k8sClient client.Client, clusterName string, kubeConfig string) (string, error) {
tmpFileName := fmt.Sprintf("/tmp/cluster-secret-%s-%s-%d.kubeconfig", clusterName, utils.RandomString(8), time.Now().UnixNano())
tmpFileName := fmt.Sprintf("/tmp/cluster-secret-%s-%d.kubeconfig", utils.RandomString(8), time.Now().UnixNano())
if err := ioutil.WriteFile(tmpFileName, []byte(kubeConfig), 0600); err != nil {
return "", errors.Wrapf(err, "failed to write kubeconfig to temp file %s", tmpFileName)
}

View File

@@ -301,6 +301,9 @@ func patchSchema(defaultSchema, customSchema []*utils.UIParameter) []*utils.UIPa
if cusSchema.Sort != 0 {
dSchema.Sort = cusSchema.Sort
}
if cusSchema.Additional != nil {
dSchema.Additional = cusSchema.Additional
}
}
}
sort.Slice(defaultSchema, func(i, j int) bool {
@@ -335,6 +338,13 @@ func renderUIParameter(key, label string, property *openapi3.SchemaRef, required
if property.Value.Properties != nil {
parameter.SubParameters = renderDefaultUISchema(property.Value)
}
if property.Value.AdditionalProperties != nil {
parameter.SubParameters = renderDefaultUISchema(property.Value.AdditionalProperties.Value)
var enable = true
value := property.Value.AdditionalProperties.Value
parameter.AdditionalParameter = renderUIParameter(value.Title, utils.FirstUpper(value.Title), property.Value.AdditionalProperties, value.Required)
parameter.Additional = &enable
}
parameter.Validate = &utils.Validate{}
parameter.Validate.DefaultValue = property.Value.Default
for _, enum := range property.Value.Enum {

View File

@@ -20,6 +20,8 @@ import (
"context"
"encoding/json"
"io/ioutil"
"path"
"strings"
"testing"
"github.com/getkin/kin-openapi/openapi3"
@@ -163,12 +165,23 @@ var _ = Describe("Test namespace usecase functions", func() {
func TestAddDefinitionUISchema(t *testing.T) {
du := NewDefinitionUsecase()
cdata, err := ioutil.ReadFile("./testdata/ui-custom-schema.yaml")
schemaFiles, err := ioutil.ReadDir("../../../../vela-templates/definitions/uischema")
if err != nil {
t.Fatal(err)
}
_, err = du.AddDefinitionUISchema(context.TODO(), "webservice", "component", string(cdata))
if err != nil {
t.Fatal(err)
for _, sf := range schemaFiles {
if !sf.IsDir() {
typeNames := strings.SplitN(sf.Name(), "-", 2)
cdata, err := ioutil.ReadFile(path.Join("../../../../vela-templates/definitions/uischema", sf.Name()))
if err != nil {
t.Fatal(err)
}
definitionName := strings.Replace(typeNames[1], path.Ext(sf.Name()), "", -1)
_, err = du.AddDefinitionUISchema(context.TODO(), definitionName, typeNames[0], string(cdata))
if err != nil {
t.Fatal(err)
}
t.Logf("create ui schema %s for %s definition", definitionName, typeNames[0])
}
}
}

View File

@@ -34,37 +34,39 @@ type DeliveryTargetUsecase interface {
DeleteDeliveryTarget(ctx context.Context, deliveryTargetName string) error
CreateDeliveryTarget(ctx context.Context, req apisv1.CreateDeliveryTargetRequest) (*apisv1.DetailDeliveryTargetResponse, error)
UpdateDeliveryTarget(ctx context.Context, deliveryTarget *model.DeliveryTarget, req apisv1.UpdateDeliveryTargetRequest) (*apisv1.DetailDeliveryTargetResponse, error)
ListDeliveryTargets(ctx context.Context, page, pageSize int, namespace string) (*apisv1.ListDeliveryTargetResponse, error)
ListDeliveryTargets(ctx context.Context, page, pageSize int, project string) (*apisv1.ListTargetResponse, error)
}
type deliveryTargetUsecaseImpl struct {
ds datastore.DataStore
ds datastore.DataStore
projectUsecase ProjectUsecase
}
// NewDeliveryTargetUsecase new DeliveryTarget usecase
func NewDeliveryTargetUsecase(ds datastore.DataStore) DeliveryTargetUsecase {
func NewDeliveryTargetUsecase(ds datastore.DataStore, projectUsecase ProjectUsecase) DeliveryTargetUsecase {
return &deliveryTargetUsecaseImpl{
ds: ds,
ds: ds,
projectUsecase: projectUsecase,
}
}
func (dt *deliveryTargetUsecaseImpl) ListDeliveryTargets(ctx context.Context, page, pageSize int, namespace string) (*apisv1.ListDeliveryTargetResponse, error) {
func (dt *deliveryTargetUsecaseImpl) ListDeliveryTargets(ctx context.Context, page, pageSize int, project string) (*apisv1.ListTargetResponse, error) {
deliveryTarget := model.DeliveryTarget{}
if namespace != "" {
deliveryTarget.Namespace = namespace
if project != "" {
deliveryTarget.Project = project
}
deliveryTargets, err := dt.ds.List(ctx, &deliveryTarget, &datastore.ListOptions{Page: page, PageSize: pageSize})
deliveryTargets, err := dt.ds.List(ctx, &deliveryTarget, &datastore.ListOptions{Page: page, PageSize: pageSize, SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}}})
if err != nil {
return nil, err
}
resp := &apisv1.ListDeliveryTargetResponse{
DeliveryTargets: []apisv1.DeliveryTargetBase{},
resp := &apisv1.ListTargetResponse{
Targets: []apisv1.DeliveryTargetBase{},
}
for _, raw := range deliveryTargets {
dt, ok := raw.(*model.DeliveryTarget)
target, ok := raw.(*model.DeliveryTarget)
if ok {
resp.DeliveryTargets = append(resp.DeliveryTargets, *convertFromDeliveryTargetModel(dt))
resp.Targets = append(resp.Targets, *(dt.convertFromDeliveryTargetModel(ctx, target)))
}
}
count, err := dt.ds.Count(ctx, &deliveryTarget, nil)
@@ -92,6 +94,7 @@ func (dt *deliveryTargetUsecaseImpl) DeleteDeliveryTarget(ctx context.Context, d
func (dt *deliveryTargetUsecaseImpl) CreateDeliveryTarget(ctx context.Context, req apisv1.CreateDeliveryTargetRequest) (*apisv1.DetailDeliveryTargetResponse, error) {
deliveryTarget := convertCreateReqToDeliveryTargetModel(req)
// check deliveryTarget name.
exit, err := dt.ds.IsExist(ctx, &deliveryTarget)
if err != nil {
@@ -101,6 +104,14 @@ func (dt *deliveryTargetUsecaseImpl) CreateDeliveryTarget(ctx context.Context, r
if exit {
return nil, bcode.ErrDeliveryTargetExist
}
// check project
project, err := dt.projectUsecase.GetProject(ctx, req.Project)
if err != nil {
return nil, err
}
deliveryTarget.Namespace = project.Namespace
deliveryTarget.Project = project.Name
if err := dt.ds.Add(ctx, &deliveryTarget); err != nil {
return nil, err
}
@@ -118,7 +129,7 @@ func (dt *deliveryTargetUsecaseImpl) UpdateDeliveryTarget(ctx context.Context, d
// DetailDeliveryTarget detail DeliveryTarget
func (dt *deliveryTargetUsecaseImpl) DetailDeliveryTarget(ctx context.Context, deliveryTarget *model.DeliveryTarget) (*apisv1.DetailDeliveryTargetResponse, error) {
return &apisv1.DetailDeliveryTargetResponse{
DeliveryTargetBase: *convertFromDeliveryTargetModel(deliveryTarget),
DeliveryTargetBase: *dt.convertFromDeliveryTargetModel(ctx, deliveryTarget),
}, nil
}
@@ -144,7 +155,6 @@ func convertUpdateReqToDeliveryTargetModel(deliveryTarget *model.DeliveryTarget,
func convertCreateReqToDeliveryTargetModel(req apisv1.CreateDeliveryTargetRequest) model.DeliveryTarget {
deliveryTarget := model.DeliveryTarget{
Name: req.Name,
Namespace: req.Namespace,
Alias: req.Alias,
Description: req.Description,
Cluster: (*model.ClusterTarget)(req.Cluster),
@@ -153,12 +163,11 @@ func convertCreateReqToDeliveryTargetModel(req apisv1.CreateDeliveryTargetReques
return deliveryTarget
}
func convertFromDeliveryTargetModel(deliveryTarget *model.DeliveryTarget) *apisv1.DeliveryTargetBase {
func (dt *deliveryTargetUsecaseImpl) convertFromDeliveryTargetModel(ctx context.Context, deliveryTarget *model.DeliveryTarget) *apisv1.DeliveryTargetBase {
var appNum int64 = 0
// TODO: query app num in target
return &apisv1.DeliveryTargetBase{
targetBase := &apisv1.DeliveryTargetBase{
Name: deliveryTarget.Name,
Namespace: deliveryTarget.Namespace,
Alias: deliveryTarget.Alias,
Description: deliveryTarget.Description,
Cluster: (*apisv1.ClusterTarget)(deliveryTarget.Cluster),
@@ -167,4 +176,13 @@ func convertFromDeliveryTargetModel(deliveryTarget *model.DeliveryTarget) *apisv
UpdateTime: deliveryTarget.UpdateTime,
AppNum: appNum,
}
project, err := dt.projectUsecase.GetProject(ctx, deliveryTarget.Project)
if err != nil {
log.Logger.Errorf("query project info failure %s", err.Error())
}
if project != nil {
targetBase.Project = convertProjectModel2Base(project)
}
return targetBase
}

View File

@@ -30,14 +30,20 @@ import (
var _ = Describe("Test delivery target usecase functions", func() {
var (
deliveryTargetUsecase *deliveryTargetUsecaseImpl
projectUsecase *projectUsecaseImpl
testProject = "target-project"
)
BeforeEach(func() {
deliveryTargetUsecase = &deliveryTargetUsecaseImpl{ds: ds}
projectUsecase = &projectUsecaseImpl{ds: ds, kubeClient: k8sClient}
deliveryTargetUsecase = &deliveryTargetUsecaseImpl{ds: ds, projectUsecase: projectUsecase}
})
It("Test CreateDeliveryTarget function", func() {
_, err := projectUsecase.CreateProject(context.TODO(), apisv1.CreateProjectRequest{Name: testProject})
Expect(err).Should(BeNil())
req := apisv1.CreateDeliveryTargetRequest{
Name: "test-delivery-target",
Namespace: "test-namespace",
Project: testProject,
Alias: "test-alias",
Description: "this is a deliveryTarget",
Cluster: &apisv1.ClusterTarget{ClusterName: "cluster-dev", Namespace: "dev"},

View File

@@ -356,11 +356,11 @@ func convertEnvbindingModelToBase(app *model.Application, envBinding *model.EnvB
dt := dte.(*model.DeliveryTarget)
dtMap[dt.Name] = dt
}
var targets []apisv1.DeliveryTargetBase
var targets []apisv1.NameAlias
for _, targetName := range envBinding.TargetNames {
dt := dtMap[targetName]
if dt != nil {
targets = append(targets, *convertFromDeliveryTargetModel(dt))
targets = append(targets, apisv1.NameAlias{Name: dt.Name, Alias: dt.Alias})
}
}
ebb := &apisv1.EnvBindingBase{

View File

@@ -1,106 +0,0 @@
/*
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 usecase
import (
"context"
"time"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
"github.com/oam-dev/kubevela/pkg/apiserver/log"
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
)
// NamespaceUsecase namespace manage usecase.
// Namespace acts as the tenant isolation model on the control side.
type NamespaceUsecase interface {
ListNamespaces(ctx context.Context) ([]apisv1.NamespaceBase, error)
CreateNamespace(ctx context.Context, req apisv1.CreateNamespaceRequest) (*apisv1.NamespaceBase, error)
}
// AnnotationDescription set namespace description in annotation
const AnnotationDescription string = "description"
// LabelCreator set namesapce creator in labels
const LabelCreator string = "creator"
type namespaceUsecaseImpl struct {
kubeClient client.Client
}
// NewNamespaceUsecase new namespace usecase
func NewNamespaceUsecase() NamespaceUsecase {
kubecli, err := clients.GetKubeClient()
if err != nil {
log.Logger.Fatalf("get kubeclient failure %s", err.Error())
}
return &namespaceUsecaseImpl{kubeClient: kubecli}
}
// ListNamespaces list controller cluster namespaces
func (n *namespaceUsecaseImpl) ListNamespaces(ctx context.Context) ([]apisv1.NamespaceBase, error) {
// TODO: Consider whether to query only namespaces created by Vela
var kubeNamespaces corev1.NamespaceList
if err := n.kubeClient.List(ctx, &kubeNamespaces, &client.ListOptions{}); err != nil {
log.Logger.Errorf("query namespace list from cluster failure %s", err.Error())
return nil, bcode.ErrNamespaceQuery
}
var namespaces []apisv1.NamespaceBase
for _, namesapce := range kubeNamespaces.Items {
namespaces = append(namespaces, apisv1.NamespaceBase{
Name: namesapce.Name,
Description: namesapce.Annotations[AnnotationDescription],
CreateTime: namesapce.CreationTimestamp.Time,
UpdateTime: namesapce.CreationTimestamp.Time,
})
}
return namespaces, nil
}
// CreateNamespace create namespace to controller cluster
func (n *namespaceUsecaseImpl) CreateNamespace(ctx context.Context, req apisv1.CreateNamespaceRequest) (*apisv1.NamespaceBase, error) {
if err := n.kubeClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: req.Name,
Labels: map[string]string{
LabelCreator: "kubevela",
},
Annotations: map[string]string{
AnnotationDescription: req.Description,
},
},
Spec: corev1.NamespaceSpec{},
}); err != nil {
if apierrors.IsAlreadyExists(err) {
return nil, bcode.ErrNamespaceIsExist
}
return nil, err
}
return &apisv1.NamespaceBase{
Name: req.Name,
Description: req.Description,
CreateTime: time.Now(),
UpdateTime: time.Now(),
}, nil
}

View File

@@ -0,0 +1,143 @@
/*
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 usecase
import (
"context"
"errors"
"fmt"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"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/bcode"
"github.com/oam-dev/kubevela/pkg/oam"
)
// ProjectUsecase project manage usecase.
type ProjectUsecase interface {
GetProject(ctx context.Context, projectName string) (*model.Project, error)
ListProjects(ctx context.Context) ([]*apisv1.ProjectBase, error)
CreateProject(ctx context.Context, req apisv1.CreateProjectRequest) (*apisv1.ProjectBase, error)
}
type projectUsecaseImpl struct {
ds datastore.DataStore
kubeClient client.Client
}
// NewProjectUsecase new project usecase
func NewProjectUsecase(ds datastore.DataStore) ProjectUsecase {
kubecli, err := clients.GetKubeClient()
if err != nil {
log.Logger.Fatalf("get kubeclient failure %s", err.Error())
}
return &projectUsecaseImpl{kubeClient: kubecli, ds: ds}
}
// GetProject get project
func (p *projectUsecaseImpl) GetProject(ctx context.Context, projectName string) (*model.Project, error) {
project := &model.Project{Name: projectName}
if err := p.ds.Get(ctx, project); err != nil {
if errors.Is(err, datastore.ErrRecordNotExist) {
return nil, bcode.ErrProjectIsNotExist
}
return nil, err
}
return project, nil
}
// ListProjects list projects
func (p *projectUsecaseImpl) ListProjects(ctx context.Context) ([]*apisv1.ProjectBase, error) {
var project = model.Project{}
entitys, err := p.ds.List(ctx, &project, &datastore.ListOptions{SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}}})
if err != nil {
return nil, err
}
var projects []*apisv1.ProjectBase
for _, entity := range entitys {
project := entity.(*model.Project)
projects = append(projects, convertProjectModel2Base(project))
}
return projects, nil
}
// CreateProject create project
func (p *projectUsecaseImpl) CreateProject(ctx context.Context, req apisv1.CreateProjectRequest) (*apisv1.ProjectBase, error) {
exist, err := p.ds.IsExist(ctx, &model.Project{Name: req.Name})
if err != nil {
log.Logger.Errorf("check project name is exist failure %s", err.Error())
return nil, bcode.ErrProjectIsExist
}
if exist {
return nil, bcode.ErrProjectIsExist
}
new := &model.Project{
Name: req.Name,
Description: req.Description,
Alias: req.Alias,
Namespace: fmt.Sprintf("project-%s", req.Name),
}
// create namespace at first
if err := p.kubeClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: new.Namespace,
Labels: map[string]string{
oam.LabelProjectNamesapce: new.Name,
},
},
Spec: corev1.NamespaceSpec{},
}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return nil, err
}
}
if err := p.ds.Add(ctx, new); err != nil {
return nil, err
}
return &apisv1.ProjectBase{
Name: new.Name,
Alias: new.Alias,
Namespace: new.Namespace,
Description: new.Description,
CreateTime: new.CreateTime,
UpdateTime: new.UpdateTime,
}, nil
}
func convertProjectModel2Base(project *model.Project) *apisv1.ProjectBase {
return &apisv1.ProjectBase{
Name: project.Name,
Namespace: project.Namespace,
Description: project.Description,
Alias: project.Alias,
CreateTime: project.CreateTime,
UpdateTime: project.UpdateTime,
}
}

View File

@@ -18,6 +18,7 @@ package usecase
import (
"context"
"fmt"
"github.com/google/go-cmp/cmp"
. "github.com/onsi/ginkgo"
@@ -26,25 +27,26 @@ import (
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
var _ = Describe("Test namespace usecase functions", func() {
var _ = Describe("Test project usecase functions", func() {
var (
namespaceUsecase *namespaceUsecaseImpl
projectUsecase *projectUsecaseImpl
)
BeforeEach(func() {
namespaceUsecase = &namespaceUsecaseImpl{kubeClient: k8sClient}
projectUsecase = &projectUsecaseImpl{kubeClient: k8sClient, ds: ds}
})
It("Test CreateNamespace function", func() {
req := apisv1.CreateNamespaceRequest{
Name: "test-namespace",
Description: "this is a namespace description 王二",
It("Test Createproject function", func() {
req := apisv1.CreateProjectRequest{
Name: "test-project",
Description: "this is a project description 王二",
}
base, err := namespaceUsecase.CreateNamespace(context.TODO(), req)
base, err := projectUsecase.CreateProject(context.TODO(), req)
Expect(err).Should(BeNil())
Expect(cmp.Diff(base.Description, req.Description)).Should(BeEmpty())
Expect(cmp.Diff(base.Namespace, fmt.Sprintf("project-%s", req.Name))).Should(BeEmpty())
})
It("Test ListNamespace function", func() {
_, err := namespaceUsecase.ListNamespaces(context.TODO())
It("Test ListProject function", func() {
_, err := projectUsecase.ListProjects(context.TODO())
Expect(err).Should(BeNil())
})
})

View File

@@ -102,14 +102,6 @@
label: ReadinessProbe
sort: 13
subParameters:
- description: How often, in seconds, to execute the probe.
jsonKey: periodSeconds
label: PeriodSeconds
sort: 100
uiType: Number
validate:
defaultValue: 10
required: true
- description: Minimum consecutive successes for the probe to be considered successful
after having failed.
jsonKey: successThreshold
@@ -182,22 +174,6 @@
label: HttpGet
sort: 100
subParameters:
- description: The endpoint, relative to the port, to which the HTTP GET request
should be directed.
jsonKey: path
label: Path
sort: 100
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
- description: ""
jsonKey: httpHeaders
label: HttpHeaders
@@ -219,6 +195,22 @@
required: true
uiType: Structs
validate: {}
- description: The endpoint, relative to the port, to which the HTTP GET request
should be directed.
jsonKey: path
label: Path
sort: 100
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: Group
validate: {}
- description: Number of seconds after the container is started before the first
@@ -230,6 +222,14 @@
validate:
defaultValue: 0
required: true
- description: How often, in seconds, to execute the probe.
jsonKey: periodSeconds
label: PeriodSeconds
sort: 100
uiType: Number
validate:
defaultValue: 10
required: true
uiType: Group
validate: {}
- description: Instructions for assessing whether the container is alive.
@@ -237,32 +237,6 @@
label: LivenessProbe
sort: 15
subParameters:
- description: Number of seconds after the container is started before the first
probe is initiated.
jsonKey: initialDelaySeconds
label: InitialDelaySeconds
sort: 100
uiType: Number
validate:
defaultValue: 0
required: true
- description: How often, in seconds, to execute the probe.
jsonKey: periodSeconds
label: PeriodSeconds
sort: 100
uiType: Number
validate:
defaultValue: 10
required: true
- description: Minimum consecutive successes for the probe to be considered successful
after having failed.
jsonKey: successThreshold
label: SuccessThreshold
sort: 100
uiType: Number
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
@@ -365,14 +339,34 @@
required: true
uiType: Group
validate: {}
- description: Number of seconds after the container is started before the first
probe is initiated.
jsonKey: initialDelaySeconds
label: InitialDelaySeconds
sort: 100
uiType: Number
validate:
defaultValue: 0
required: true
- description: How often, in seconds, to execute the probe.
jsonKey: periodSeconds
label: PeriodSeconds
sort: 100
uiType: Number
validate:
defaultValue: 10
required: true
- description: Minimum consecutive successes for the probe to be considered successful
after having failed.
jsonKey: successThreshold
label: SuccessThreshold
sort: 100
uiType: Number
validate:
defaultValue: 1
required: true
uiType: Group
validate: {}
- description: Specify image pull secrets for your service
jsonKey: imagePullSecrets
label: ImagePullSecrets
sort: 100
uiType: Strings
validate: {}
- description: Which port do you want customer traffic sent to
disable: true
jsonKey: port
@@ -382,6 +376,12 @@
validate:
defaultValue: 80
required: true
- description: Specify image pull secrets for your service
jsonKey: imagePullSecrets
label: ImagePullSecrets
sort: 100
uiType: Strings
validate: {}
- description: Declare volumes and volumeMounts
disable: true
jsonKey: volumes

View File

@@ -43,18 +43,27 @@ var _ = Describe("Test workflow usecase functions", func() {
var (
workflowUsecase *workflowUsecaseImpl
appUsecase *applicationUsecaseImpl
projectUsecase *projectUsecaseImpl
testProject = "workflow-project"
)
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,
}}
projectUsecase = &projectUsecaseImpl{ds: ds, kubeClient: k8sClient}
appUsecase = &applicationUsecaseImpl{ds: ds, kubeClient: k8sClient,
apply: apply.NewAPIApplicator(k8sClient),
projectUsecase: projectUsecase,
envBindingUsecase: &envBindingUsecaseImpl{
ds: ds,
workflowUsecase: workflowUsecase,
}}
})
It("Test CreateWorkflow function", func() {
_, err := projectUsecase.CreateProject(context.TODO(), apisv1.CreateProjectRequest{Name: testProject})
Expect(err).Should(BeNil())
reqApp := apisv1.CreateApplicationRequest{
Name: appName,
Namespace: "default",
Project: testProject,
Description: "this is a test app",
EnvBinding: []*apisv1.EnvBinding{{
Name: "dev",
@@ -62,9 +71,8 @@ var _ = Describe("Test workflow usecase functions", func() {
TargetNames: []string{"dev-target"},
}},
}
_, err := appUsecase.CreateApplication(context.TODO(), reqApp)
_, err = appUsecase.CreateApplication(context.TODO(), reqApp)
Expect(err).Should(BeNil())
req := apisv1.CreateWorkflowRequest{
Name: "test-workflow-1",
Description: "this is a workflow",

View File

@@ -16,8 +16,8 @@ limitations under the License.
package bcode
// ErrNamespaceQuery query namespace failure from k8s api
var ErrNamespaceQuery = NewBcode(500, 30001, "query namespace list from cluster failure")
// ErrProjectIsExist project name is exist
var ErrProjectIsExist = NewBcode(400, 30001, "project name is exist")
// ErrNamespaceIsExist namespace name is exist
var ErrNamespaceIsExist = NewBcode(400, 30002, "namespace name is exist")
// ErrProjectIsNotExist project is not exist
var ErrProjectIsNotExist = NewBcode(404, 30002, "project is not exist")

View File

@@ -0,0 +1,17 @@
/*
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 bcode

View File

@@ -29,10 +29,12 @@ type UIParameter struct {
Validate *Validate `json:"validate,omitempty"`
JSONKey string `json:"jsonKey"`
UIType string `json:"uiType"`
// means only can be read.
// means disable parameter in ui
Disable *bool `json:"disable,omitempty"`
SubParameterGroupOption []GroupOption `json:"subParameterGroupOption,omitempty"`
SubParameters []*UIParameter `json:"subParameters,omitempty"`
AdditionalParameter *UIParameter `json:"additionalParameter,omitempty"`
Additional *bool `json:"additional,omitempty"`
}
// GroupOption define multiple data structure composition options.

View File

@@ -505,7 +505,7 @@ func (c *applicationWebService) createApplication(req *restful.Request, res *res
func (c *applicationWebService) listApplications(req *restful.Request, res *restful.Response) {
apps, err := c.applicationUsecase.ListApplications(req.Request.Context(), apis.ListApplicatioOptions{
Namespace: req.QueryParameter("namespace"),
Project: req.QueryParameter("project"),
TargetName: req.QueryParameter("targetName"),
Query: req.QueryParameter("query"),
})

View File

@@ -51,7 +51,7 @@ type DeliveryTargetWebService struct {
// GetWebService get web service
func (dt *DeliveryTargetWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/deliveryTargets").
ws.Path(versionPrefix+"/targets").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for deliveryTarget manage")
@@ -61,11 +61,11 @@ func (dt *DeliveryTargetWebService) GetWebService() *restful.WebService {
ws.Route(ws.GET("/").To(dt.listDeliveryTargets).
Doc("list deliveryTarget").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("namesapce", "Query the delivery target belonging to a namespace").DataType("string")).
Param(ws.QueryParameter("project", "Query the target belong to project").DataType("string")).
Param(ws.QueryParameter("page", "Page for paging").DataType("integer")).
Param(ws.QueryParameter("pageSize", "PageSize for paging").DataType("integer")).
Returns(200, "", apis.ListDeliveryTargetResponse{}).
Writes(apis.ListDeliveryTargetResponse{}).Do(returns200, returns500))
Returns(200, "", apis.ListTargetResponse{}).
Writes(apis.ListTargetResponse{}).Do(returns200, returns500))
ws.Route(ws.POST("/").To(dt.createDeliveryTarget).
Doc("create deliveryTarget").
@@ -204,7 +204,7 @@ func (dt *DeliveryTargetWebService) listDeliveryTargets(req *restful.Request, re
bcode.ReturnError(req, res, err)
return
}
deliveryTargets, err := dt.deliveryTargetUsecase.ListDeliveryTargets(req.Request.Context(), page, pageSize, req.QueryParameter("namespace"))
deliveryTargets, err := dt.deliveryTargetUsecase.ListDeliveryTargets(req.Request.Context(), page, pageSize, req.QueryParameter("project"))
if err != nil {
bcode.ReturnError(req, res, err)
return

View File

@@ -26,54 +26,54 @@ import (
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
)
type namespaceWebService struct {
namespaceUsecase usecase.NamespaceUsecase
type projectWebService struct {
projectUsecase usecase.ProjectUsecase
}
// NewNamespaceWebService new namespace webservice
func NewNamespaceWebService(namespaceUsecase usecase.NamespaceUsecase) WebService {
return &namespaceWebService{namespaceUsecase: namespaceUsecase}
// NewProjectWebService new project webservice
func NewProjectWebService(projectUsecase usecase.ProjectUsecase) WebService {
return &projectWebService{projectUsecase: projectUsecase}
}
func (n *namespaceWebService) GetWebService() *restful.WebService {
func (n *projectWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/namespaces").
ws.Path(versionPrefix+"/projects").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for namespace manage")
Doc("api for project manage")
tags := []string{"namespace"}
tags := []string{"project"}
ws.Route(ws.GET("/").To(n.listNamespaces).
Doc("list all namespaces").
ws.Route(ws.GET("/").To(n.listprojects).
Doc("list all projects").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(200, "", apis.ListNamespaceResponse{}).
Writes(apis.ListNamespaceResponse{}))
Returns(200, "", apis.ListProjectResponse{}).
Writes(apis.ListProjectResponse{}))
ws.Route(ws.POST("/").To(n.createNamespace).
Doc("create namespace").
ws.Route(ws.POST("/").To(n.createproject).
Doc("create a project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(apis.CreateNamespaceRequest{}).
Returns(200, "", apis.NamespaceDetailResponse{}).
Writes(apis.NamespaceDetailResponse{}))
Reads(apis.CreateProjectRequest{}).
Returns(200, "", apis.ProjectBase{}).
Writes(apis.ProjectBase{}))
return ws
}
func (n *namespaceWebService) listNamespaces(req *restful.Request, res *restful.Response) {
namespaces, err := n.namespaceUsecase.ListNamespaces(req.Request.Context())
func (n *projectWebService) listprojects(req *restful.Request, res *restful.Response) {
projects, err := n.projectUsecase.ListProjects(req.Request.Context())
if err != nil {
bcode.ReturnError(req, res, err)
return
}
if err := res.WriteEntity(apis.ListNamespaceResponse{Namespaces: namespaces}); err != nil {
if err := res.WriteEntity(apis.ListProjectResponse{Projects: projects}); err != nil {
bcode.ReturnError(req, res, err)
return
}
}
func (n *namespaceWebService) createNamespace(req *restful.Request, res *restful.Response) {
func (n *projectWebService) createproject(req *restful.Request, res *restful.Response) {
// Verify the validity of parameters
var createReq apis.CreateNamespaceRequest
var createReq apis.CreateProjectRequest
if err := req.ReadEntity(&createReq); err != nil {
bcode.ReturnError(req, res, err)
return
@@ -83,7 +83,7 @@ func (n *namespaceWebService) createNamespace(req *restful.Request, res *restful
return
}
// Call the usecase layer code
namespaceBase, err := n.namespaceUsecase.CreateNamespace(req.Request.Context(), createReq)
projectBase, err := n.projectUsecase.CreateProject(req.Request.Context(), createReq)
if err != nil {
log.Logger.Errorf("create application failure %s", err.Error())
bcode.ReturnError(req, res, err)
@@ -91,7 +91,7 @@ func (n *namespaceWebService) createNamespace(req *restful.Request, res *restful
}
// Write back response data
if err := res.WriteEntity(apis.NamespaceDetailResponse{NamespaceBase: *namespaceBase}); err != nil {
if err := res.WriteEntity(projectBase); err != nil {
bcode.ReturnError(req, res, err)
return
}

View File

@@ -28,34 +28,34 @@ var _ = Describe("Test validate function", func() {
It("Test check name validate ", func() {
Expect(cmp.Diff(nameRegexp.MatchString("///Asd asda "), false)).Should(BeEmpty())
var app0 = apisv1.CreateApplicationRequest{
Name: "a",
Namespace: "namespace",
Name: "a",
Project: "namespace",
}
err := validate.Struct(&app0)
Expect(err).ShouldNot(BeNil())
var app1 = apisv1.CreateApplicationRequest{
Name: "Asdasd",
Namespace: "namespace",
Name: "Asdasd",
Project: "namespace",
}
err = validate.Struct(&app1)
Expect(err).ShouldNot(BeNil())
var app2 = apisv1.CreateApplicationRequest{
Name: "asdasd asdasd ++",
Namespace: "namespace",
Name: "asdasd asdasd ++",
Project: "namespace",
}
err = validate.Struct(&app2)
Expect(err).ShouldNot(BeNil())
var app3 = apisv1.CreateApplicationRequest{
Name: "asdasd",
Namespace: "namespace",
Name: "asdasd",
Project: "namespace",
}
err = validate.Struct(&app3)
Expect(err).Should(BeNil())
var app4 = apisv1.CreateApplicationRequest{
Name: "asdasd-asdasd",
Namespace: "namespace",
Name: "asdasd-asdasd",
Project: "namespace",
}
err = validate.Struct(&app4)
Expect(err).Should(BeNil())

View File

@@ -60,17 +60,17 @@ func returns500(b *restful.RouteBuilder) {
func Init(ds datastore.DataStore) {
clusterUsecase := usecase.NewClusterUsecase(ds)
workflowUsecase := usecase.NewWorkflowUsecase(ds)
deliveryTargetUsecase := usecase.NewDeliveryTargetUsecase(ds)
namespaceUsecase := usecase.NewNamespaceUsecase()
projectUsecase := usecase.NewProjectUsecase(ds)
deliveryTargetUsecase := usecase.NewDeliveryTargetUsecase(ds, projectUsecase)
oamApplicationUsecase := usecase.NewOAMApplicationUsecase()
velaQLUsecase := usecase.NewVelaQLUsecase()
definitionUsecase := usecase.NewDefinitionUsecase()
addonUsecase := usecase.NewAddonUsecase()
envBindingUsecase := usecase.NewEnvBindingUsecase(ds, workflowUsecase, definitionUsecase)
applicationUsecase := usecase.NewApplicationUsecase(ds, workflowUsecase, envBindingUsecase, deliveryTargetUsecase, definitionUsecase)
applicationUsecase := usecase.NewApplicationUsecase(ds, workflowUsecase, envBindingUsecase, deliveryTargetUsecase, definitionUsecase, projectUsecase)
RegistWebService(NewClusterWebService(clusterUsecase))
RegistWebService(NewApplicationWebService(applicationUsecase, envBindingUsecase, workflowUsecase))
RegistWebService(NewNamespaceWebService(namespaceUsecase))
RegistWebService(NewProjectWebService(projectUsecase))
RegistWebService(NewDefinitionWebservice(definitionUsecase))
RegistWebService(NewAddonWebService(addonUsecase))
RegistWebService(NewEnabledAddonWebService(addonUsecase))

View File

@@ -19,10 +19,13 @@ package http
import (
"context"
"crypto/tls"
"crypto/x509"
"io"
"net/http"
"time"
"cuelang.org/go/cue"
"github.com/pkg/errors"
"github.com/oam-dev/kubevela/pkg/builtin/registry"
)
@@ -54,7 +57,13 @@ func (c *HTTPCmd) Run(meta *registry.Meta) (res interface{}, err error) {
method = meta.String("method")
u = meta.String("url")
)
var r io.Reader
var (
r io.Reader
client = &http.Client{
Transport: &http.Transport{},
Timeout: time.Second * 3,
}
)
if obj := meta.Obj.Lookup("request"); obj.Exists() {
if v := obj.Lookup("body"); v.Exists() {
r, err = v.Reader()
@@ -83,7 +92,43 @@ func (c *HTTPCmd) Run(meta *registry.Meta) (res interface{}, err error) {
}
req.Header = header
req.Trailer = trailer
resp, err := c.Client.Do(req)
if tlsConfig := meta.Obj.Lookup("tls_config"); tlsConfig.Exists() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
NextProtos: []string{"http/1.1"},
},
}
ca := tlsConfig.Lookup("ca")
if caCrt, err := ca.String(); err != nil {
return nil, errors.WithMessage(err, "parse ca")
} else {
pool := x509.NewCertPool()
pool.AppendCertsFromPEM([]byte(caCrt))
tr.TLSClientConfig.RootCAs = pool
}
cert := tlsConfig.Lookup("client_crt")
key := tlsConfig.Lookup("client_key")
if cert.Exists() && key.Exists() {
crtData, err := cert.String()
if err != nil {
return nil, err
}
keyData, err := key.String()
if err != nil {
return nil, err
}
cliCrt, err := tls.X509KeyPair([]byte(crtData), []byte(keyData))
if err != nil {
return nil, errors.WithMessage(err, "parse client keypair")
}
tr.TLSClientConfig.Certificates = []tls.Certificate{cliCrt}
}
client.Transport = tr
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}

View File

@@ -17,6 +17,9 @@ limitations under the License.
package http
import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"net"
@@ -27,6 +30,7 @@ import (
"cuelang.org/go/cue"
"github.com/bmizerany/assert"
"github.com/oam-dev/kubevela/pkg/builtin/http/testdata"
"github.com/oam-dev/kubevela/pkg/builtin/registry"
)
@@ -96,6 +100,29 @@ func TestHTTPCmdRun(t *testing.T) {
}
func TestHTTPSRun(t *testing.T) {
s := newMockHttpsServer()
defer s.Close()
r := cue.Runtime{}
reqInst, err := r.Compile("-", `method: "GET"
url: "https://127.0.0.1:8443/api/v1/token?val=test-token"`)
if err != nil {
t.Fatal(err)
}
reqInst, _ = reqInst.Fill(decodeCert(testdata.MockCerts.Ca), "tls_config", "ca")
reqInst, _ = reqInst.Fill(decodeCert(testdata.MockCerts.ClientCrt), "tls_config", "client_crt")
reqInst, _ = reqInst.Fill(decodeCert(testdata.MockCerts.ClientKey), "tls_config", "client_key")
runner, _ := newHTTPCmd(cue.Value{})
got, err := runner.Run(&registry.Meta{Obj: reqInst.Value()})
if err != nil {
t.Error(err)
}
body := (got.(map[string]interface{}))["body"].(string)
assert.Equal(t, "{\"token\":\"test-token\"}", body)
}
// NewMock mock the http server
func NewMock() *httptest.Server {
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -118,3 +145,40 @@ func NewMock() *httptest.Server {
ts.Start()
return ts
}
func newMockHttpsServer() *httptest.Server {
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
fmt.Printf("Expected 'GET' request, got '%s'", r.Method)
}
if r.URL.EscapedPath() != "/api/v1/token" {
fmt.Printf("Expected request to '/person', got '%s'", r.URL.EscapedPath())
}
r.ParseForm()
token := r.Form.Get("val")
tokenBytes, _ := json.Marshal(map[string]interface{}{"token": token})
w.WriteHeader(http.StatusOK)
w.Write(tokenBytes)
}))
l, _ := net.Listen("tcp", "127.0.0.1:8443")
ts.Listener.Close()
ts.Listener = l
pool := x509.NewCertPool()
pool.AppendCertsFromPEM([]byte(decodeCert(testdata.MockCerts.Ca)))
cert, _ := tls.X509KeyPair([]byte(decodeCert(testdata.MockCerts.ServerCrt)), []byte(decodeCert(testdata.MockCerts.ServerKey)))
ts.TLS = &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{cert},
NextProtos: []string{"http/1.1"},
}
ts.StartTLS()
return ts
}
func decodeCert(in string) string {
out, _ := base64.StdEncoding.DecodeString(in)
return string(out)
}

39
pkg/builtin/http/testdata/certs.go vendored Normal file
View File

@@ -0,0 +1,39 @@
/*
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 testdata
var (
_ = `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBcHRMN21JQmdaaDVEd1FYYkJXaHRSeURGK01qaytQeStNU1Vyck5pc1EyeXF4cnphCjhEeWw5a0pRWW5oMnVYVFV1RnBzbDRhM1J5dEJaVkdrMDNQT0RXOWJIblR2QUNPZHJjMnR2WmR5ZXRXU1ZtQ2cKOHhuc3Y3WHVQS0VGb0VwakVaMDdCWjY2blFIRDg2MHFMeGFGRWtMNHk2MzU5SThWVlRBYk5RejVPQ3dmM29mUQpMN0JPL2RVNUJtRTNXTDhhVHF3SXRSa0hJeE5pWCs4OWU2Z3dCY3RHdUZLR3ZacFhGaW1VeXA1Y0crVWI2RzkyCi9KUTZJWm45dGFIZ3NFYWIvWUNwZ2U1Rkp5WVR1dzVlakhRajRYNVh3ZVRKU0tsN0UwUmZhMjl5VnM5aXdhNDQKcmVNSzVXR2hVUFl6T1o0MURGZnU1MmJnMjVPODF6QWJFSFpLUndJREFRQUJBb0lCQUNUVUJ2OFB1RGhURGhvYQp0Tk5vemxjWmdSci9IcTFvL29QUzlPVmZvQWZ5Z1hFR1dEOFk1SHFOQVRuNzVobmpGT0x0ODNNd0psM3J5ckFYCmFnL1VUUFRpVkhkUTBVSnltbWk0TTFiYmpFWlp4OGlSNUhaR2p1Rnp4SGhXQSt2ekFCUHZaZ3hEa21iKzhNZG0KdngxT0YycUVwbkF3cERHOU5MUnR2bFBqM1ZEczhVODU2c2hWeDdBdFE3RGJUWkQwdEpsQ0pzTzR5TitjL1oxOApiRzJKNDB2RWFLalVGTE9HNitScE43NEZLeGtvOFJJejZxeERQMk5VMUg1ajVVVi9tZXdRdDBsRTNqbEc5MmcvCnVwTngyK0xnYUkrMWhCR3AzV2prQlRWcWloZWxrUk5XZkNLczdXOHJtYk83V3MvK2cwcVNidnAvUjBWQWpQd0MKdGt4SENFRUNnWUVBM2s3K0hOVkNZY0YxN2k2ZTJnNTJDVHV0cDJBYzkvSUNMdVJzNGFRZlB4MkxFc2VDalJnNgovaHNsOGpLbmRDS1JQdTBJbkoxckF4NzVrZXBKZWpWcTBIbkFEN2VtcVhuMDN0UjJmb3hvbkxBOEtQMzdSSnJqClhlZ0k5NiswWUU3QUY5dWZqQVhPeXpFU3RQVkNSVDlJOFRMSlEwRFhraW56bDhVUm5aZ1RjdmtDZ1lFQXdCdFYKLzNnbFR5Z0syNTFpMS9FakdrK3I3THF5NzdCY29LVzZHTm91K0FiQ3gxalhZVE1URDNTRXVyMzBueHB6VWNkdgpIbEI1NkI2Q1JmRkdXN0o1U0tkeXI5WmhQUUtITUQ1TkZhbm00S1F4NmZmVFhubExRdnhhT2c2TFRnTDRSdjFyCjVaeUdEbDhBKzRRckpNVk1OOTZOVEY1VDB0TXRUaHlIVnpLbHR6OENnWUJ3Q3BQYjZFZUtpVHhzakthVzg4N2QKbkd4Sy9RL2NqdVkyeC8xd1E0MVQvQW5KcnkvRytMMVNzRkFSbnlIeVVER3Y2enI1NUFTNUQvVnNhdzRaUDY3VAozMmpEQXlaR0tDY1gzekRSV3VhbWdkUHdQUUZVZEZPL1VtQ2lwTFZlREpLWDg2S1hxWjJ0bnMvMHo5OVVreTZxCkVaU0tCclllL25HOHZoL0FzNUtwMFFLQmdRQzFxT1BncWFkMk8rSlFuSHE4d3UwejAwVTduYXpabFlkeDdtV1YKWExUdm04MFNuME5FU2Z6ckwzN1g3QXJuYlNiQm5YckpTc2FNcGxVQWVORFVvMmVuT1pqdENDZDVmdXVCeGxnMApkUzY3SE9tS1d1ekl1S0JmM3F3Zm5HTkV5UEFvaVRvL3JZempDQm13dmVIaWFxUFJiU1Ztb3doWEk1VUMrVjFPCktybWtGd0tCZ1FEVERDWlg1WWQ5ZUdXZG1OM3pUU2Z6YkRrRkxqZkYyYTVBK2lDL281TmoyVmpHRG4xTjRvVUwKajF0dVZLb0xoVjhVZzd0Lzc4V0V0UkRnK1p3QVZhSW84bE1zU244dDVQNFFrY2pkSDI4bHpFaTQwWHpxQkF0Lwpoalppb1pNN2ZHUmJWK29yakZSQ2tZWnNaMUdua2FrbG5Mdk4vYVRuM25HV2tEZjFaZGM0YVE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==` //ca.key
caCrt = `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyakNDQVpZQ0NRRDV0K3E3ZkswSlVEQU5CZ2txaGtpRzl3MEJBUXNGQURBWk1SY3dGUVlEVlFRRERBNHEKTG10bGRXSmxkbVZzWVM1cGJ6QWVGdzB5TVRFeE1qSXdPRFEyTlRsYUZ3MHpOVEE0TURFd09EUTJOVGxhTUJreApGekFWQmdOVkJBTU1EaW91YTJWMVltVjJaV3hoTG1sdk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBCk1JSUJDZ0tDQVFFQXB0TDdtSUJnWmg1RHdRWGJCV2h0UnlERitNamsrUHkrTVNVcnJOaXNRMnlxeHJ6YThEeWwKOWtKUVluaDJ1WFRVdUZwc2w0YTNSeXRCWlZHazAzUE9EVzliSG5UdkFDT2RyYzJ0dlpkeWV0V1NWbUNnOHhucwp2N1h1UEtFRm9FcGpFWjA3Qlo2Nm5RSEQ4NjBxTHhhRkVrTDR5NjM1OUk4VlZUQWJOUXo1T0N3ZjNvZlFMN0JPCi9kVTVCbUUzV0w4YVRxd0l0UmtISXhOaVgrODllNmd3QmN0R3VGS0d2WnBYRmltVXlwNWNHK1ViNkc5Mi9KUTYKSVpuOXRhSGdzRWFiL1lDcGdlNUZKeVlUdXc1ZWpIUWo0WDVYd2VUSlNLbDdFMFJmYTI5eVZzOWl3YTQ0cmVNSwo1V0doVVBZek9aNDFERmZ1NTJiZzI1TzgxekFiRUhaS1J3SURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCCkFRQWJ1dGZjbENOZVhTaldBR0NSb2tyTVN2Z0VvMlZEdnE4Y1lEN3hIT3gzRllQRWE0Rk01VC9uSXVsNGJxSCsKY09mOCtMOTZXTGNUUnpNRnhrMmNKT2VKV3hFMDkzcDN2dHRZMFUrOGZ4T1FIY3JxK1N3U0dPTUpWTHhEcGtPNApscFVpc0JYOENGQld5VG9vN05WRy9FZGRVS1FHa2ttaGJMdXJIZStHTnFmT0VpS01GYm1PRHBzZ1Zqc0oxK2hPCjZDWG8zZW01Mlh4eVZqbGtoNzBJK29UMW5PeGFYSEhwK0NNT2JPSXkzcFhMejJROWNmRU1uTlZrVTBDMmFaeksKS1ViMGZXOTlpbjBJRmlUd0NkQlhRTlRpMzh6bVEvUUlEYlJEQTJFREtMa2pZRzdUUFR4Wm9xL04rQUQ3ZElLWQpyaE56TXB6cGhhRGR4Ymt3cmlHRGQ5TEkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==`
serverKey = `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBemdMMTJpL0gwaXk5MGhLb0sySUwrbnIvRDB0RGlPdVlwYk5NUktCTTJyMGtCblhCClJUdU1peWNWMUd5OGlwQ1FLMmwwV1E3dDJpTStLT1BBTFYxQ0thNEtpTlg5M015cWlmVFVBc3YzemRtNkhiZFMKa3owcUlOYTBoZTBaclA3M3g0YWZHRmJ2SXRwU1pWQThwSUhrc281SHFhcTRndTcwVUhRSlhZcFIrRjlKY3l3eAppWTZ4S0x6QWNGcjlsdktZdlVaWitRR1FUbWh4TFFtKzI5cUJsZXIvRGpEQzlkZjM2blFkSU5wdUpIak1tZXI2CnZQVU5CekQ5OWliT3NpYVBxMlo1VHRuY3U0TlRzKzlLN09BWnhLK1d4VVp6c3pKbnhHNjgxR010MXJ1anBIVlMKSGIrYmh2ek9aRmt6aFhWVE5wL0FYMElNdy92K3hpZzl3WXkyK1FJREFRQUJBb0lCQVFESmFObUdWRnB1NERGQgpGZDUyYzZnMFhsWEpWUk1VNVFsYlR2MU14cy84dHhobWZHL1ZTUS94NStlT3hEUmM0Rk1qTGptQzdIYWNZd0pkCnBiVDRaUW5QaUFsaW1KeFdaMzUvMiszL1Fmem1zMndqcTF3KytYaWJuRzNuMWRQWmIzaytDQjY1QkIxT0hOYWIKbUtPQlRrRVNWTW81VmVDSW1pZ2dGQ0luNHBpYlVvSXpHcmdabVRsTmlQTjFPb2FNNk9IcEorZDVGNDFNdGYwbgpJYjAyTVYzdUtZb1hqUWtFYytBL3B3WDJ0TVlGUTMza3NwTlZjSURnYU4zUWRsb3IxQXhDN0xQaStKeTZNelY1CmJ4VDhlcFhZN2VmUFhqblR0VmVHQWFUNThJSFdWS29ncmt6V21xdHROMUtzc2RBWGpja1NWRksxL0U5V1c4Q28KWDBTa3VpUFJBb0dCQVA1SERCSDZkRURqbVp0TVVFeHEwNWlwcWxSbFhnYUdYT01lT0VIZ1VSVzhEdnJiNC9zLwo4cEswUWZCUUpkYTIwT1d0dVprSDNYWEVnNktjL0NyMWZIQU9uNElmOFI1NlJNRUpWUnhvTzlBZWZVem9nZjAvCndWUlpmZmRUTkhKV2E3VExJaVdNdXpmY2k0bTdldnZkNkpUS3lzTlRvREJuemM0ZFpzcGhxWHh0QW9HQkFNOW8KTnBqSmxsZDBrUENicFRtRjZMRGpBMzAvaS9DRzlVNEoxaUFrQno3SzA2TU9ENDA3TlZ5QTV0V2p5QjlSTThnbwpMcjZhK1g3MDN2YWVMZDZQcDY2UnlDbzU4RWFhcFk2SFQvTGVNSGRzUllEdk9PU2pOT0FtbkJxcFFVR1Z2ZVhTClpCN2srclpVK3g2UktEblFod3crZGsveUZkZmJ5VmxhTDRKVFZiVTlBb0dCQVBOYUNYbzNTUVZGRGFBc0EvbHUKajMxZWUwMzBDVzJUTDlpSTlteE5neXlhNDNjLzlNdGpZd0wyRXRrcnkxclhjY3N1WFI3UkFTaVJYeTNFc2kxbQo3YVhNeU9sZktvTHhuMVZqV2hvcXczdWxnbU9WYmJweVJ0TTBKck1KNVhxN3JLN0ZiYk9rSVJVUU5GY25uMGJuCkZJMDZHNTJlTGdQRmhKaUxXUEc5VDlodEFvR0JBS1JrWEluamxqZEJYRFJwbVo4clpWRDJ6bWd5dXc5dFdQZCsKMG1wdFJCVGdITGtyeHVYUlhTMHh1a1R4YVFoeGkxS0ZqdTlpMUlodFBHQks1ZDUzREpoUVVsQXQxaVdRSTlNQgpxenU4SXJ3MVpDMmE3d1JCM0FJaWVDNmxvdVNCOUo4NWtFUHdpRXVHdGZmM1krUFhSWU5ONnViWTRibFRLcGVZCjVQa3Vaa3VkQW9HQVozTHg0UGNnK3RSR0dsclR0WllXZmNxT3FDcUIya0NCa2tDVnlvWW9qSzM4a21CNVJ0QmQKZzBnMTc5TGdUTWE0Y0ZWRUhyZC9xU2RRQVZiTmxyRDh4MjJNYnJMam1aa05aOXQ1alpJSWQwRVRxYTJBNC8rNApOV05HeU12b0ttTmMxcFd2UEJiT1R1RHp2WEg3YnZzbXAzallucjJQU09WaFU1RGdJRHpEQTJBPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==`
serverCrt = `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMzekNDQWNlZ0F3SUJBZ0lKQU55SVoyTElxQTNqTUEwR0NTcUdTSWIzRFFFQkJRVUFNQmt4RnpBVkJnTlYKQkFNTURpb3VhMlYxWW1WMlpXeGhMbWx2TUI0WERUSXhNVEV5TWpBNU16UXpORm9YRFRNMU1EZ3dNVEE1TXpRegpORm93R0RFV01CUUdBMVVFQXd3TktpNXJkV0psZG1Wc1lTNXBiekNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFECmdnRVBBRENDQVFvQ2dnRUJBTTRDOWRvdng5SXN2ZElTcUN0aUMvcDYvdzlMUTRqcm1LV3pURVNnVE5xOUpBWjEKd1VVN2pJc25GZFJzdklxUWtDdHBkRmtPN2RvalBpamp3QzFkUWltdUNvalYvZHpNcW9uMDFBTEw5ODNadWgyMwpVcE05S2lEV3RJWHRHYXorOThlR254aFc3eUxhVW1WUVBLU0I1TEtPUjZtcXVJTHU5RkIwQ1YyS1VmaGZTWE1zCk1ZbU9zU2k4d0hCYS9aYnltTDFHV2ZrQmtFNW9jUzBKdnR2YWdaWHEvdzR3d3ZYWDkrcDBIU0RhYmlSNHpKbnEKK3J6MURRY3cvZlltenJJbWo2dG1lVTdaM0x1RFU3UHZTdXpnR2NTdmxzVkdjN015WjhSdXZOUmpMZGE3bzZSMQpVaDIvbTRiOHptUlpNNFYxVXphZndGOUNETVA3L3NZb1BjR010dmtDQXdFQUFhTXJNQ2t3Q1FZRFZSMFRCQUl3CkFEQUxCZ05WSFE4RUJBTUNCZUF3RHdZRFZSMFJCQWd3Qm9jRWZ3QUFBVEFOQmdrcWhraUc5dzBCQVFVRkFBT0MKQVFFQUJNbUhSZG4rS043QWZTL3JicHI2dGx6SHBoRFJud29KR0NxSkZYZjdabUN1TEF3NzVsTlhxOUxka2NJeApSZXhleXk2cnk2SmF6RGN4OVltWHVnZzFtTTlrWE5kTmc0NmVSangzRk4vL2FRUFJOMHNuTDVOaXRyM0kvdEJmCkxNdlduUisrQ2tZSnFtM1NuTnRicVR0cDhodTZKWnVRUVh2WWM0ZEg5VmJRM2d3UzFSUzdhQ0RBZHlLZEhnSFQKZmN3VnNqZmk2TzhLdlROaG43aU1LWERZQUhiWXh3ekpsdjBEWFhuZjhmRlo3U09FT3VkbGM5Y3hOQW0xVlBjZAo1YXcwR0hvbWMxNTdHU244UmpWenlJOHRPdGE4WU9uaU9SOE5qNElzMExRQXF3VjJ1OU52Zkg3bkJMUjg3d1Z2CmFxUmxaWE5uOG5qcWgwdzZkc3BUWjRwQWFBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==`
clientCrt = `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5VENDQWJHZ0F3SUJBZ0lKQU55SVoyTElxQTNpTUEwR0NTcUdTSWIzRFFFQkJRVUFNQmt4RnpBVkJnTlYKQkFNTURpb3VhMlYxWW1WMlpXeGhMbWx2TUI0WERUSXhNVEV5TWpBNE5UVTFNRm9YRFRNMU1EZ3dNVEE0TlRVMQpNRm93RmpFVU1CSUdBMVVFQXd3TGRHVnpkRjlzYVdwcFlXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRQzhZNGU1ZElYd3FaL1dWOFVLMEhVc2toRlRmTytxMC96VU9CZVl0amplNFQrTmhlc2oKS0tkLzhWLzBYZTY5ck5CYXE3RVBhYUFReDVYYTF1aGh2SWRXU2F2QWhmaTgwd3lXSy9reUtKR0xsaTZleTZtLwpjZkdxRVJ5eUtnc2NoZWFrQ3dCajArZkxnVUZ5aVM0MzVubnVZZ2Y0MXFmRVJ1azREUExDVk9uRE13dXBmQkdyClNacmY2U0R3Z0V3SnV2QVlhQ0owcE91NkovRzhkMVNOb3I4UFlGQjBFbGl2d2ZESk9CRjFvMEg2elYzMHZ1bVoKRzM0anpoNjh3aThPNG1TZjZCbi9XMlEyckNvY1FlSE9nUVRGcHVtdC9qYy9lMnhlRFpOd3RpS25OMTdWa3o1QwpXVGxpUEZuQlRWTWZCeHEyOGNIemtzaTVBRDZ5bVlRMkNzcTVBZ01CQUFHakZ6QVZNQk1HQTFVZEpRUU1NQW9HCkNDc0dBUVVGQndNQ01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQnpKRnFlUk9BRDZ0ZkVrNElsNGxvbDI4OGIKaFZMMnRXdThXbGtDdHFQaFNOR0hkeWJQcGdLL3dCajQzS3FGcFRMVGo0TStDT0cwR08xZDVMK1lROHdHOHJGQQpHWTd3ZndQLzRlenpzSzNocmI5NnNpdm04TUZqdXRzSEdzenFWRkZ0UXBNWkhBTm5FQXY0ZkxGSEtQM0ZubmkyCnpjYmwrVXNQWFk3QU5NelpOelIwQVdLWmxwbm5hMUpuQWtzQnBBTzlweFRKOU55MzhVNlc0SERrN2gyVk5BUHAKbGpxRmNoYXdjTkN1MDIzV2hhWWxuNGowTG9NRlh0NDJNMXgxL2R4SnQxNUlnNFB5LysrbmZRbmtvN09vSmVpVAppb0lNc3VBcmNJaG1MSU8zZzFTNVJtNzJ6NDUwSXV0blFWQUc3MVQ0alZyR3libHhnMWpGVjFXWHJ1V2MKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==`
clientKey = `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdkdPSHVYU0Y4S21mMWxmRkN0QjFMSklSVTN6dnF0UDgxRGdYbUxZNDN1RS9qWVhyCkl5aW5mL0ZmOUYzdXZhelFXcXV4RDJtZ0VNZVYydGJvWWJ5SFZrbXJ3SVg0dk5NTWxpdjVNaWlSaTVZdW5zdXAKdjNIeHFoRWNzaW9MSElYbXBBc0FZOVBueTRGQmNva3VOK1o1N21JSCtOYW54RWJwT0F6eXdsVHB3ek1McVh3UgpxMG1hMytrZzhJQk1DYnJ3R0dnaWRLVHJ1aWZ4dkhkVWphSy9EMkJRZEJKWXI4SHd5VGdSZGFOQitzMWQ5TDdwCm1SdCtJODRldk1JdkR1SmtuK2daLzF0a05xd3FIRUhoem9FRXhhYnByZjQzUDN0c1hnMlRjTFlpcHpkZTFaTSsKUWxrNVlqeFp3VTFUSHdjYXR2SEI4NUxJdVFBK3NwbUVOZ3JLdVFJREFRQUJBb0lCQUhYYjZ1aTZucVUrNmRHbQpYWTd6ZGFzcHd3OHhaWnZCUGpiaTFOaGtnRlhvSStOOWVlc29Id3FyVHZYSjRuZmw2d0FlMUFvcGNjdXRvZklrCmE0UGg5K1dpOTRIZUR3ekxHTi9HcVFPWlg5MHRXd05idFZvaGhpaDR4alFzbTREL3dKaTJqVXJuSXVndGVHMlkKcDBLdnZXN0hBK2ZKRzNKdlRxOFRZcmp6ZUwvMlYzUnRSbk1oNldjcWI0cWpRb2NZWkR3VU43MVBVYURrUTRLSApWdHNNSjloc0dBUDFDVFRQckZZR1daRUZiN0xtZGNRemJyWVZyQnhwaGRoZGpqUXBjVzAySjZHU1ZrY0NMeFkvCnVRYnpZS0RkUXU1SHJKbVpiNjlFRmJWZHp3OTh3alIvNyt0dUhmdlJzYkUxRWdKWlQxNkhSUHEwbW1mMWxHM3EKNm9ZbnNCRUNnWUVBNVd2SEE4bWliMVpYWiszaXN3SUh0SlZ5WGJWM0Y4ejZ5UHRaK2ZNa1ljY3BBb3g0SDRTbgp1azllN2NlN0lhMDJueXlwTmlIaXZMRXZ3dGlqNjlBQ3I1WWpMMzlDMUlYbjJYMUg3V2FKaHF2K21zOW5ybmV0CmRqY0RtZXJRRHBVU0IzbXFLQlhXY2dVaXA4NUVYMlo5SzhPbnRhNXV6MG8vb2R4a0VTdWM3M1VDZ1lFQTBqYlAKUVBjY1N4RmRsVDFEcjg0WWhkUDJzQUJ6YUpoWDNzUm44NnhBTWk4aW9PY05lMTh1cVFBdk4rQWpRQUFndlkyOQo3dVdRcXB1SlFueG9NcGJMVjdjSkw2aHBlekpEL2lhZDVzREpyMC9jTWVhK3JSWVFQK2xxSW9YZTI2TlZPZnNHCmZGNkpHZUdvUGpRTmVKM1FSV0NaMEo0UkRob242YjZCWHVFVTZiVUNnWUVBczlCRGpiNXQ1K0crWkNEWlBBQnQKVmFhRW10bnQyK08yOCt1OVcrQ3NOVTdKMzh1Rkl2N3dEMkRDUUkvNUphNERUOExMWlRndDVFTGo4azJtUE44dQpHNzBMR3VFZDJrQ1J0YTh4dnVwTkJCYXVXVndTSVhaL3FGWDZKcHNhTXpPM2k5QmFBMDBLWlJlTlVBU2xKampJCkJwTTFVWHJFTXdnNDAzNVBsLzJjNVRrQ2dZQnRmL054cWNicEs0Q043cjNGWkJ2T0NsMmp6SGhSY1puRUJwY0gKalNCYmc4WUwvbzg5UnBWdG54VDVqQjJRaHdDRy9NQ0ZJcnU2d3c0NnZjY2hJditGRDJrUGxEQnQ1ZjhZOGxDcQpGSjU2WGFVYnNWQjlwTktPR0M0YkVaVEc0RXZTeWZuVTZ3R0xvOG9ack0rZmxzVVlmbnRnK2hWMFBSZXhZSFRQClVYdXRTUUtCZ1FDck9WeHBqNXFKdmMyaUZrMXNoWDRXeDBYbHpzZzI3QkdUNy9zYmtrMHMxT1ViZEZueTErTUkKNUVpVU1xUHM5TU5IOWZxbHNmMEJCS1BXMW0wVFAvSHo2OHFrRm80cnJrZVlMYmYvYVN2OWFJNnRodGJTWUoyUQpKTm9qeW1Ea2ZFbmNDOTNsMUV5alF0Y1lJSGNDWFRGMlhibXVwdEtlT2lqeC84c3FTOUVkRmc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==`
MockCerts = struct {
Ca string
ServerKey string
ServerCrt string
ClientCrt string
ClientKey string
}{
Ca: caCrt,
ServerCrt: serverCrt,
ServerKey: serverKey,
ClientKey: clientKey,
ClientCrt: clientCrt,
}
)

View File

@@ -20,6 +20,8 @@ import (
"encoding/json"
"strings"
"github.com/oam-dev/kubevela/pkg/workflow/providers/http"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -53,6 +55,7 @@ func (h *AppHandler) GenerateApplicationSteps(ctx context.Context,
kube.Install(handlerProviders, h.r.Client, h.Dispatch, h.Delete)
oamProvider.Install(handlerProviders, app, h.applyComponentFunc(
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
http.Install(handlerProviders, h.r.Client, app.Namespace)
taskDiscover := tasks.NewTaskDiscover(handlerProviders, h.r.pd, h.r.Client, h.r.dm)
multiclusterProvider.Install(handlerProviders, h.r.Client, app)
terraformProvider.Install(handlerProviders, app, func(comp common.ApplicationComponent) (*appfile.Workload, error) {

View File

@@ -34,6 +34,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/policy/envbinding"
errors3 "github.com/oam-dev/kubevela/pkg/utils/errors"
)
@@ -62,6 +63,20 @@ func ensureResourceTrackerCRDInstalled(ctx context.Context, c client.Client, clu
return nil
}
// ensureVelaSystemNamespaceInstalled ensures vela namespace to be installed in child cluster
func ensureVelaSystemNamespaceInstalled(ctx context.Context, c client.Client, clusterName string, createNamespace string) error {
remoteCtx := ContextWithClusterName(ctx, clusterName)
if err := c.Get(remoteCtx, types2.NamespacedName{Name: createNamespace}, &v1.Namespace{}); err != nil {
if !errors2.IsNotFound(err) {
return errors.Wrapf(err, "failed to check vela-system ")
}
if err = c.Create(remoteCtx, &v1.Namespace{ObjectMeta: v12.ObjectMeta{Name: createNamespace}}); err != nil {
return errors.Wrapf(err, "failed to create vela-system namespace")
}
}
return nil
}
// ensureClusterNotExists checks if child cluster has already been joined, if joined, error is returned
func ensureClusterNotExists(ctx context.Context, c client.Client, clusterName string) error {
secret := &v1.Secret{}
@@ -173,6 +188,11 @@ func JoinClusterByKubeConfig(_ctx context.Context, k8sClient client.Client, kube
_ = k8sClient.Delete(_ctx, secret)
return cluster, errors.Wrapf(err, "failed to ensure resourcetracker crd installed in cluster %s", clusterName)
}
if err := ensureVelaSystemNamespaceInstalled(_ctx, k8sClient, clusterName, types.DefaultKubeVelaNS); err != nil {
return nil, errors.Wrapf(err, "failed to create vela namespace in cluster %s", clusterName)
}
return cluster, nil
}

View File

@@ -64,6 +64,9 @@ const (
// LabelAddonName indicates the name of the corresponding Addon
LabelAddonName = "addons.oam.dev/name"
// LabelProject Namesapce records the project name of namespace
LabelProjectNamesapce = "namespace.oam.dev/project"
)
const (

View File

@@ -9,6 +9,7 @@
header: [string]: string
trailer: [string]: string
}
tls_config?: secret: string
response: {
body: string
header?: [string]: [...string]

View File

@@ -17,7 +17,13 @@ limitations under the License.
package http
import (
"context"
"encoding/base64"
"strings"
"cuelang.org/go/cue"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/builtin"
"github.com/oam-dev/kubevela/pkg/builtin/registry"
@@ -33,10 +39,61 @@ const (
)
type provider struct {
cli client.Client
ns string
}
// Do process http request.
func (h *provider) Do(ctx wfContext.Context, v *value.Value, act types.Action) error {
tlsConfig, err := v.LookupValue("tls_config")
if err == nil {
secretName, err := tlsConfig.GetString("secret")
if err != nil {
return err
}
objectKey := client.ObjectKey{
Namespace: h.ns,
Name: secretName,
}
index := strings.Index(secretName, "/")
if index > 0 {
objectKey.Namespace = secretName[:index-1]
objectKey.Name = secretName[index:]
}
secret := new(v1.Secret)
if err := h.cli.Get(context.Background(), objectKey, secret); err != nil {
return err
}
if ca, ok := secret.Data["ca.crt"]; ok {
caData, err := base64.StdEncoding.DecodeString(string(ca))
if err != nil {
return err
}
if err := v.FillObject(string(caData), "tls_config", "ca"); err != nil {
return err
}
}
if clientCert, ok := secret.Data["client.crt"]; ok {
certData, err := base64.StdEncoding.DecodeString(string(clientCert))
if err != nil {
return err
}
if err := v.FillObject(string(certData), "tls_config", "client_crt"); err != nil {
return err
}
}
if clientKey, ok := secret.Data["client.key"]; ok {
keyData, err := base64.StdEncoding.DecodeString(string(clientKey))
if err != nil {
return err
}
if err := v.FillObject(string(keyData), "tls_config", "client_key"); err != nil {
return err
}
}
}
ret, err := builtin.RunTaskByKey("http", cue.Value{}, &registry.Meta{
Obj: v.CueValue(),
})
@@ -47,8 +104,11 @@ func (h *provider) Do(ctx wfContext.Context, v *value.Value, act types.Action) e
}
// Install register handlers to provider discover.
func Install(p providers.Providers) {
prd := &provider{}
func Install(p providers.Providers, cli client.Client, ns string) {
prd := &provider{
cli: cli,
ns: ns,
}
p.Register(ProviderName, map[string]providers.Handler{
"do": prd.Do,
})

View File

@@ -17,13 +17,25 @@ limitations under the License.
package http
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/crossplane/crossplane-runtime/pkg/test"
"gotest.tools/assert"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/builtin/http/testdata"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/workflow/providers"
)
@@ -102,7 +114,7 @@ request:{
func TestInstall(t *testing.T) {
p := providers.NewProviders()
Install(p)
Install(p, nil, "")
h, ok := p.GetHandler("http", "do")
assert.Equal(t, ok, true)
assert.Equal(t, h != nil, true)
@@ -134,3 +146,68 @@ func runMockServer(shutdown chan struct{}) {
}
}
}
func TestHTTPSDo(t *testing.T) {
s := newMockHttpsServer()
defer s.Close()
cli := &test.MockClient{
MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
secret := obj.(*v1.Secret)
*secret = v1.Secret{
Data: map[string][]byte{
"ca.crt": []byte(testdata.MockCerts.Ca),
"client.crt": []byte(testdata.MockCerts.ClientCrt),
"client.key": []byte(testdata.MockCerts.ClientKey),
},
}
return nil
},
}
v, err := value.NewValue(`
method: "GET"
url: "https://127.0.0.1:8443/api/v1/token?val=test-token"
`, nil, "")
assert.NilError(t, err)
assert.NilError(t, v.FillObject("certs", "tls_config", "secret"))
prd := &provider{cli, "default"}
err = prd.Do(nil, v, nil)
assert.NilError(t, err)
}
func newMockHttpsServer() *httptest.Server {
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
fmt.Printf("Expected 'GET' request, got '%s'", r.Method)
}
if r.URL.EscapedPath() != "/api/v1/token" {
fmt.Printf("Expected request to '/person', got '%s'", r.URL.EscapedPath())
}
r.ParseForm()
token := r.Form.Get("val")
tokenBytes, _ := json.Marshal(map[string]interface{}{"token": token})
w.WriteHeader(http.StatusOK)
w.Write(tokenBytes)
}))
l, _ := net.Listen("tcp", "127.0.0.1:8443")
ts.Listener.Close()
ts.Listener = l
decode := func(in string) []byte {
out, _ := base64.StdEncoding.DecodeString(in)
return out
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(decode(testdata.MockCerts.Ca))
cert, _ := tls.X509KeyPair(decode(testdata.MockCerts.ServerCrt), decode(testdata.MockCerts.ServerKey))
ts.TLS = &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{cert},
NextProtos: []string{"http/1.1"},
}
ts.StartTLS()
return ts
}

View File

@@ -76,7 +76,6 @@ func suspend(step v1beta1.WorkflowStep, opt *types.GeneratorOptions) (types.Task
func NewTaskDiscover(providerHandlers providers.Providers, pd *packages.PackageDiscover, cli client.Client, dm discoverymapper.DiscoveryMapper) types.TaskDiscover {
// install builtin provider
workspace.Install(providerHandlers)
http.Install(providerHandlers)
convert.Install(providerHandlers)
email.Install(providerHandlers)
templateLoader := template.NewWorkflowStepTemplateLoader(cli, dm)
@@ -122,7 +121,7 @@ func NewViewTaskDiscover(pd *packages.PackageDiscover, cli client.Client, apply
query.Install(handlerProviders, cli)
time.Install(handlerProviders)
kube.Install(handlerProviders, cli, apply, delete)
http.Install(handlerProviders)
http.Install(handlerProviders, cli, viewNs)
convert.Install(handlerProviders)
email.Install(handlerProviders)

View File

@@ -20,6 +20,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
@@ -41,7 +42,7 @@ var _ = Describe("Test application rest api", func() {
defer GinkgoRecover()
var req = apisv1.CreateApplicationRequest{
Name: appName,
Namespace: appProject,
Project: appProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -60,7 +61,7 @@ var _ = Describe("Test application rest api", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(cmp.Diff(appBase.Name, req.Name)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Description, req.Description)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Namespace, req.Namespace)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Project.Namespace, fmt.Sprintf("project-%s", appProject))).Should(BeEmpty())
Expect(cmp.Diff(appBase.Labels["test"], req.Labels["test"])).Should(BeEmpty())
})
@@ -80,7 +81,7 @@ var _ = Describe("Test application rest api", func() {
Expect(err).Should(Succeed())
var req = apisv1.CreateApplicationRequest{
Name: appName,
Namespace: appProject,
Project: appProject,
Description: "this is a test app",
Icon: "",
Labels: map[string]string{"test": "true"},
@@ -99,7 +100,6 @@ var _ = Describe("Test application rest api", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(cmp.Diff(appBase.Name, req.Name)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Description, req.Description)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Namespace, req.Namespace)).Should(BeEmpty())
Expect(cmp.Diff(appBase.Labels["test"], req.Labels["test"])).Should(BeEmpty())
})
@@ -138,8 +138,8 @@ var _ = Describe("Test application rest api", func() {
var namespace = "default"
// create target
var createTarget = apisv1.CreateDeliveryTargetRequest{
Name: targetName,
Namespace: appProject,
Name: targetName,
Project: appProject,
Cluster: &apisv1.ClusterTarget{
ClusterName: "local",
Namespace: namespace,
@@ -147,7 +147,7 @@ var _ = Describe("Test application rest api", func() {
}
bodyByte, err := json.Marshal(createTarget)
Expect(err).ShouldNot(HaveOccurred())
res, err := http.Post("http://127.0.0.1:8000/api/v1/deliveryTargets", "application/json", bytes.NewBuffer(bodyByte))
res, err := http.Post("http://127.0.0.1:8000/api/v1/targets", "application/json", bytes.NewBuffer(bodyByte))
Expect(err).ShouldNot(HaveOccurred())
Expect(res).ShouldNot(BeNil())
Expect(cmp.Diff(res.StatusCode, 200)).Should(BeEmpty())
@@ -186,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: appName + "-" + envName, Namespace: appProject}, &oam)
err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: appName + "-" + envName, Namespace: fmt.Sprintf("project-%s", 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())

View File

@@ -19,6 +19,7 @@ package e2e_apiserver_test
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/google/go-cmp/cmp"
@@ -28,38 +29,39 @@ import (
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
var _ = Describe("Test namespace rest api", func() {
It("Test create namespace", func() {
var _ = Describe("Test project rest api", func() {
It("Test create project", func() {
defer GinkgoRecover()
var req = apisv1.CreateNamespaceRequest{
var req = apisv1.CreateProjectRequest{
Name: "dev-team",
Description: "开发环境租户",
Description: "KubeVela Project",
}
bodyByte, err := json.Marshal(req)
Expect(err).ShouldNot(HaveOccurred())
res, err := http.Post("http://127.0.0.1:8000/api/v1/namespaces", "application/json", bytes.NewBuffer(bodyByte))
res, err := http.Post("http://127.0.0.1:8000/api/v1/projects", "application/json", bytes.NewBuffer(bodyByte))
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 namespaceBase apisv1.NamespaceBase
err = json.NewDecoder(res.Body).Decode(&namespaceBase)
var projectBase apisv1.ProjectBase
err = json.NewDecoder(res.Body).Decode(&projectBase)
Expect(err).ShouldNot(HaveOccurred())
Expect(cmp.Diff(namespaceBase.Name, req.Name)).Should(BeEmpty())
Expect(cmp.Diff(namespaceBase.Description, req.Description)).Should(BeEmpty())
Expect(cmp.Diff(projectBase.Name, req.Name)).Should(BeEmpty())
Expect(cmp.Diff(projectBase.Namespace, fmt.Sprintf("project-%s", req.Name))).Should(BeEmpty())
Expect(cmp.Diff(projectBase.Description, req.Description)).Should(BeEmpty())
})
It("Test list namespace", func() {
It("Test list project", func() {
defer GinkgoRecover()
res, err := http.Get("http://127.0.0.1:8000/api/v1/namespaces")
res, err := http.Get("http://127.0.0.1:8000/api/v1/projects")
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 namespaces apisv1.ListNamespaceResponse
err = json.NewDecoder(res.Body).Decode(&namespaces)
var projects apisv1.ListProjectResponse
err = json.NewDecoder(res.Body).Decode(&projects)
Expect(err).ShouldNot(HaveOccurred())
})
})

View File

@@ -17,7 +17,9 @@ limitations under the License.
package e2e_apiserver_test
import (
"bytes"
"context"
"encoding/json"
"errors"
"net/http"
"testing"
@@ -31,6 +33,7 @@ import (
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
arest "github.com/oam-dev/kubevela/pkg/apiserver/rest"
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
var k8sClient client.Client
@@ -72,11 +75,19 @@ var _ = BeforeSuite(func() {
By("wait for api server to start")
Eventually(
func() error {
res, err := http.Get("http://127.0.0.1:8000/api/v1/namespaces")
res, err := http.Get("http://127.0.0.1:8000/api/v1/projects")
if err != nil {
return err
}
if res.StatusCode == http.StatusOK {
var req = apisv1.CreateProjectRequest{
Name: appProject,
Description: "test project",
}
bodyByte, err := json.Marshal(req)
Expect(err).ShouldNot(HaveOccurred())
_, err = http.Post("http://127.0.0.1:8000/api/v1/projects", "application/json", bytes.NewBuffer(bodyByte))
Expect(err).ShouldNot(HaveOccurred())
return nil
}
return errors.New("rest service not ready")

View File

@@ -0,0 +1,23 @@
- jsonKey: writeConnectionSecretToRef
disable: true
- jsonKey: providerRef
disable: true
- jsonKey: region
disable: true
- jsonKey: instance_name
label: InstanceName
sort: 1
- jsonKey: database_name
label: DatabaseName
sort: 2
- jsonKey: account_name
label: AccountName
sort: 3
- jsonKey: password
sort: 4
- jsonKey: allocate_public_connection
label: AllocatePublicConnection
sort: 5
- jsonKey: deleteResource
label: DeleteResource
sort: 10

View File

@@ -0,0 +1,2 @@
- jsonKey: objects
uiType: K8sObjectsCode

View File

@@ -0,0 +1,168 @@
- uiType: ImageInput
jsonKey: image
label: Image
sort: 1
- jsonKey: restart
sort: 2
uiType: Select
validate:
options:
- label: Never
value: Never
- label: OnFailure
value: OnFailure
- jsonKey: count
sort: 3
uiType: Number
- jsonKey: memory
uiType: MemoryNumber
sort: 4
label: Memory Request&Limit
- uiType: CPUNumber
jsonKey: cpu
sort: 5
label: CPU Request&Limit
- description: Specify image pull policy for your service
jsonKey: imagePullPolicy
label: Image Pull Policy
uiType: Select
sort: 7
validate:
options:
- label: IfNotPresent
value: IfNotPresent
- label: Always
value: Always
- label: Never
value: Never
- jsonKey: cmd
label: CMD
sort: 9
- jsonKey: env
sort: 10
label: ENV
subParameterGroupOption:
- label: Add By Value
keys:
- name
- value
- label: Add By Secret
keys:
- name
- valueFrom
subParameters:
- jsonKey: valueFrom
label: Secret Selector
uiType: InnerGroup
subParameters:
- jsonKey: configMapKeyRef
disable: true
- jsonKey: secretKeyRef
uiType: Ignore
subParameters:
- jsonKey: name
label: Secret Name
uiType: SecretSelect
sort: 1
- jsonKey: key
label: Secret Key
uiType: SecretKeySelect
sort: 3
uiType: Structs
- jsonKey: ports
label: Service Ports
sort: 11
subParameters:
- jsonKey: port
sort: 1
- jsonKey: protocol
sort: 2
- jsonKey: expose
sort: 3
- jsonKey: volumeMounts
label: Persistent Storage
description: "Set the path and type that the service needs to persist."
uiType: Group
subParameters:
- jsonKey: secret
disable: true
- jsonKey: pvc
sort: 1
- jsonKey: hostPath
sort: 3
- jsonKey: emptyDir
sort: 5
sort: 12
- jsonKey: readinessProbe
uiType: Group
label: ReadinessProbe
subParameters:
- jsonKey: hostAliases
disable: true
- jsonKey: timeoutSeconds
sort: 1
- jsonKey: failureThreshold
sort: 4
- jsonKey: initialDelaySeconds
sort: 7
- jsonKey: periodSeconds
sort: 9
- jsonKey: successThreshold
sort: 11
- jsonKey: exec
sort: 14
- jsonKey: httpGet
sort: 19
subParameters:
- jsonKey: port
sort: 1
- jsonKey: path
sort: 3
- jsonKey: httpHeaders
sort: 5
- jsonKey: tcpSocket
sort: 19
sort: 13
- jsonKey: livenessProbe
uiType: Group
label: LivenessProbe
subParameters:
- jsonKey: hostAliases
disable: true
- jsonKey: timeoutSeconds
sort: 1
- jsonKey: failureThreshold
sort: 4
- jsonKey: initialDelaySeconds
sort: 7
- jsonKey: periodSeconds
sort: 9
- jsonKey: successThreshold
sort: 11
- jsonKey: exec
sort: 14
- jsonKey: httpGet
sort: 19
subParameters:
- jsonKey: port
sort: 1
- jsonKey: path
sort: 3
- jsonKey: httpHeaders
sort: 5
- jsonKey: tcpSocket
sort: 19
sort: 15
- jsonKey: annotations
sort: 19
- jsonKey: lables
sort: 21
- jsonKey: volumes
disable: true

View File

@@ -1,6 +1,6 @@
- uiType: ImageInput
jsonKey: image
label: Application Image
label: Image
sort: 1
- jsonKey: memory
uiType: MemoryNumber
@@ -26,11 +26,11 @@
- jsonKey: exposeType
sort: 8
- jsonKey: cmd
label: Container Start Command
label: CMD
sort: 9
- jsonKey: env
sort: 10
label: Environments
label: ENV
subParameterGroupOption:
- label: Add By Value
keys:
@@ -62,9 +62,28 @@
- jsonKey: ports
label: Service Ports
sort: 11
subParameters:
- jsonKey: port
sort: 1
- jsonKey: protocol
sort: 2
- jsonKey: expose
sort: 3
- jsonKey: volumeMounts
label: Persistent Storage
description: "Set the path and type that the service needs to persist."
uiType: Group
subParameters:
- jsonKey: configMap
disable: true
- jsonKey: secret
disable: true
- jsonKey: pvc
sort: 1
- jsonKey: hostPath
sort: 3
- jsonKey: emptyDir
sort: 5
sort: 12
- jsonKey: readinessProbe
@@ -73,6 +92,30 @@
subParameters:
- jsonKey: hostAliases
disable: true
- jsonKey: timeoutSeconds
sort: 1
- jsonKey: failureThreshold
sort: 4
- jsonKey: initialDelaySeconds
sort: 7
- jsonKey: periodSeconds
sort: 9
- jsonKey: successThreshold
sort: 11
- jsonKey: exec
sort: 14
- jsonKey: httpGet
sort: 19
subParameters:
- jsonKey: port
sort: 1
- jsonKey: path
sort: 3
- jsonKey: httpHeaders
sort: 5
- jsonKey: tcpSocket
sort: 19
sort: 13
- jsonKey: livenessProbe