mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-01 01:00:38 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a783393ebd | ||
|
|
a19ed0b510 | ||
|
|
03223aa786 | ||
|
|
55c8dad116 | ||
|
|
38c57c38c8 | ||
|
|
7f734e9479 | ||
|
|
7814232b7c |
44
.github/workflows/definition-lint.yml
vendored
Normal file
44
.github/workflows/definition-lint.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Definition-Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
workflow_dispatch: {}
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.19'
|
||||
|
||||
jobs:
|
||||
definition-doc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup K3d
|
||||
uses: nolar/setup-k3d-k3s@v1.0.9
|
||||
with:
|
||||
version: v1.20
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Definition Doc generate check
|
||||
run: |
|
||||
go build -o docgen hack/docgen/def/gen.go
|
||||
./docgen --type=comp --force-example-doc --path=./comp-def-check.md
|
||||
./docgen --type=trait --force-example-doc --path=./trait-def-check.md
|
||||
./docgen --type=wf --force-example-doc --path=./wf-def-check.md
|
||||
./docgen --type=policy --force-example-doc --path=./policy-def-check.md
|
||||
8
e2e/addon/mock/testdata/mock-dep-addon/metadata.yaml
vendored
Normal file
8
e2e/addon/mock/testdata/mock-dep-addon/metadata.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
name: mock-dep-addon
|
||||
version: v1.0.0
|
||||
description: Vela test addon named mock-dep-addon
|
||||
icon: https://www.test.com/icon
|
||||
url: https://www.test.com
|
||||
|
||||
dependencies:
|
||||
- name: mock-be-dep-addon
|
||||
@@ -60,4 +60,13 @@ entries:
|
||||
urls:
|
||||
- http://127.0.0.1:9098/helm/bar-v2.0.0.tgz
|
||||
version: v2.0.0
|
||||
mock-be-dep-addon:
|
||||
- created: "2022-10-29T09:11:16.865230605Z"
|
||||
description: Vela test addon named mock-be-dep-addon
|
||||
home: https://www.test.com/icon
|
||||
icon: https://www.test.com
|
||||
name: mock-be-dep-addon
|
||||
urls:
|
||||
- http://127.0.0.1:9098/helm/mock-be-dep-addon-v1.0.0.tgz
|
||||
version: v1.0.0
|
||||
generated: "2022-06-15T13:17:04.733573+08:00"
|
||||
BIN
e2e/addon/mock/testrepo/helm-repo/mock-be-dep-addon-v1.0.0.tgz
Normal file
BIN
e2e/addon/mock/testrepo/helm-repo/mock-be-dep-addon-v1.0.0.tgz
Normal file
Binary file not shown.
@@ -149,6 +149,12 @@ var helmHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Reques
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
case strings.Contains(req.URL.Path, "mock-be-dep-addon-v1.0.0.tgz"):
|
||||
file, err := os.ReadFile("./e2e/addon/mock/testrepo/helm-repo/mock-be-dep-addon-v1.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ func main() {
|
||||
defdir := flag.String("def-dir", "", "path of definition dir")
|
||||
tp := flag.String("type", "", "choose one of the definition to print")
|
||||
i18nfile := flag.String("i18n", "../kubevela.io/static/reference-i18n.json", "file path of i18n data")
|
||||
forceExample := flag.Bool("force-example-doc", false, "example must be provided for definitions")
|
||||
flag.Parse()
|
||||
|
||||
if *i18nfile != "" {
|
||||
@@ -52,21 +53,29 @@ func main() {
|
||||
fmt.Println("you must specify a type with definition ref path specified ")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
opt := mods.Options{
|
||||
Path: *path,
|
||||
Location: *location,
|
||||
DefDir: *defdir,
|
||||
ForceExamples: *forceExample,
|
||||
}
|
||||
|
||||
fmt.Printf("creating docs with args path=%s, location=%s, defdir=%s, type=%s.\n", *path, *location, *defdir, *tp)
|
||||
switch types.CapType(*tp) {
|
||||
case types.TypeComponentDefinition, "component", "comp":
|
||||
mods.ComponentDef(ctx, c, path, location, *defdir)
|
||||
mods.ComponentDef(ctx, c, opt)
|
||||
case types.TypeTrait:
|
||||
mods.TraitDef(ctx, c, path, location, *defdir)
|
||||
mods.TraitDef(ctx, c, opt)
|
||||
case types.TypePolicy:
|
||||
mods.PolicyDef(ctx, c, path, location, *defdir)
|
||||
mods.PolicyDef(ctx, c, opt)
|
||||
case types.TypeWorkflowStep, "workflow", "wf":
|
||||
mods.WorkflowDef(ctx, c, path, location, *defdir)
|
||||
mods.WorkflowDef(ctx, c, opt)
|
||||
case "":
|
||||
mods.ComponentDef(ctx, c, path, location, *defdir)
|
||||
mods.TraitDef(ctx, c, path, location, *defdir)
|
||||
mods.PolicyDef(ctx, c, path, location, *defdir)
|
||||
mods.WorkflowDef(ctx, c, path, location, *defdir)
|
||||
mods.ComponentDef(ctx, c, opt)
|
||||
mods.TraitDef(ctx, c, opt)
|
||||
mods.PolicyDef(ctx, c, opt)
|
||||
mods.WorkflowDef(ctx, c, opt)
|
||||
default:
|
||||
fmt.Printf("type %s not supported\n", *tp)
|
||||
os.Exit(1)
|
||||
|
||||
@@ -19,7 +19,6 @@ package mods
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -60,12 +59,13 @@ title: 内置组件列表
|
||||
` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// ComponentDef generate component def reference doc
|
||||
func ComponentDef(ctx context.Context, c common.Args, path, location *string, defdir string) {
|
||||
if defdir == "" {
|
||||
defdir = ComponentDefDir
|
||||
func ComponentDef(ctx context.Context, c common.Args, opt Options) {
|
||||
if opt.DefDir == "" {
|
||||
opt.DefDir = ComponentDefDir
|
||||
}
|
||||
ref := &docgen.MarkdownReference{
|
||||
AllInOne: true,
|
||||
AllInOne: true,
|
||||
ForceExample: opt.ForceExamples,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypeComponentDefinition || capability.Category != types.CUECategory {
|
||||
return false
|
||||
@@ -74,9 +74,9 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
files, err := os.ReadDir(opt.DefDir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
fmt.Println("read dir err", opt.DefDir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
@@ -96,19 +96,20 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de
|
||||
return
|
||||
}
|
||||
ref.DiscoveryMapper = dm
|
||||
if *path != "" {
|
||||
if opt.Path != "" {
|
||||
ref.I18N = &docgen.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomComponentHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path)
|
||||
return
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
if opt.Location == "" || opt.Location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -116,7 +117,7 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de
|
||||
}
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
if opt.Location == "" || opt.Location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomComponentHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPathZh); err != nil {
|
||||
|
||||
@@ -19,7 +19,6 @@ package mods
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -58,12 +57,13 @@ title: 内置策略列表
|
||||
` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// PolicyDef generate policy def reference doc
|
||||
func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdir string) {
|
||||
if defdir == "" {
|
||||
defdir = PolicyDefDir
|
||||
func PolicyDef(ctx context.Context, c common.Args, opt Options) {
|
||||
if opt.DefDir == "" {
|
||||
opt.DefDir = PolicyDefDir
|
||||
}
|
||||
ref := &docgen.MarkdownReference{
|
||||
AllInOne: true,
|
||||
AllInOne: true,
|
||||
ForceExample: opt.ForceExamples,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypePolicy || capability.Category != types.CUECategory {
|
||||
return false
|
||||
@@ -72,9 +72,9 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
files, err := os.ReadDir(opt.DefDir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
fmt.Println("read dir err", opt.DefDir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
@@ -86,20 +86,21 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi
|
||||
},
|
||||
CustomDocHeader: CustomPolicyHeaderEN,
|
||||
}
|
||||
ref.Remote = &docgen.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
if *path != "" {
|
||||
ref.Local = &docgen.FromLocal{Path: PolicyDefDir}
|
||||
if opt.Path != "" {
|
||||
ref.I18N = &docgen.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomPolicyHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path)
|
||||
return
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
if opt.Location == "" || opt.Location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -107,7 +108,7 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi
|
||||
}
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
if opt.Location == "" || opt.Location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomPolicyHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPathZh); err != nil {
|
||||
|
||||
@@ -19,7 +19,6 @@ package mods
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -58,12 +57,13 @@ title: 内置运维特征列表
|
||||
` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// TraitDef generate trait def reference doc
|
||||
func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir string) {
|
||||
if defdir == "" {
|
||||
defdir = TraitDefDir
|
||||
func TraitDef(ctx context.Context, c common.Args, opt Options) {
|
||||
if opt.DefDir == "" {
|
||||
opt.DefDir = TraitDefDir
|
||||
}
|
||||
ref := &docgen.MarkdownReference{
|
||||
AllInOne: true,
|
||||
AllInOne: true,
|
||||
ForceExample: opt.ForceExamples,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypeTrait || capability.Category != types.CUECategory {
|
||||
return false
|
||||
@@ -72,9 +72,9 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
files, err := os.ReadDir(opt.DefDir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
fmt.Println("read dir err", opt.DefDir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
@@ -90,20 +90,20 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir
|
||||
Path: TraitDefDir,
|
||||
}
|
||||
|
||||
if *path != "" {
|
||||
if opt.Path != "" {
|
||||
ref.I18N = &docgen.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path)
|
||||
} else {
|
||||
// Generate to default path depends on language
|
||||
if *location == "" || *location == "en" {
|
||||
if opt.Location == "" || opt.Location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -111,7 +111,7 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
if opt.Location == "" || opt.Location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil {
|
||||
|
||||
25
hack/docgen/def/mods/types.go
Normal file
25
hack/docgen/def/mods/types.go
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mods
|
||||
|
||||
// Options defines the doc generate options
|
||||
type Options struct {
|
||||
Path string
|
||||
Location string
|
||||
DefDir string
|
||||
ForceExamples bool
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package mods
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -58,12 +57,13 @@ title: 内置工作流步骤列表
|
||||
` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// WorkflowDef generate workflow def reference doc
|
||||
func WorkflowDef(ctx context.Context, c common.Args, path, location *string, defdir string) {
|
||||
if defdir == "" {
|
||||
defdir = WorkflowDefDir
|
||||
func WorkflowDef(ctx context.Context, c common.Args, opt Options) {
|
||||
if opt.DefDir == "" {
|
||||
opt.DefDir = WorkflowDefDir
|
||||
}
|
||||
ref := &docgen.MarkdownReference{
|
||||
AllInOne: true,
|
||||
AllInOne: true,
|
||||
ForceExample: opt.ForceExamples,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
|
||||
if capability.Type != types.TypeWorkflowStep || capability.Category != types.CUECategory {
|
||||
@@ -74,9 +74,9 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
files, err := os.ReadDir(opt.DefDir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
fmt.Println("read dir err", opt.DefDir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
@@ -88,21 +88,22 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def
|
||||
},
|
||||
CustomDocHeader: CustomWorkflowHeaderEN,
|
||||
}
|
||||
ref.Remote = &docgen.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
ref.Local = &docgen.FromLocal{Path: WorkflowDefDir}
|
||||
|
||||
if *path != "" {
|
||||
if opt.Path != "" {
|
||||
ref.I18N = &docgen.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomWorkflowHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path)
|
||||
return
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
if opt.Location == "" || opt.Location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -110,7 +111,7 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def
|
||||
}
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
if opt.Location == "" || opt.Location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomWorkflowHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPathZh); err != nil {
|
||||
|
||||
@@ -932,10 +932,12 @@ type Installer struct {
|
||||
|
||||
dryRun bool
|
||||
dryRunBuff *bytes.Buffer
|
||||
|
||||
registries []Registry
|
||||
}
|
||||
|
||||
// NewAddonInstaller will create an installer for addon
|
||||
func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r *Registry, args map[string]interface{}, cache *Cache, opts ...InstallOption) Installer {
|
||||
func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r *Registry, args map[string]interface{}, cache *Cache, registries []Registry, opts ...InstallOption) Installer {
|
||||
i := Installer{
|
||||
ctx: ctx,
|
||||
config: config,
|
||||
@@ -946,6 +948,7 @@ func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *
|
||||
cache: cache,
|
||||
dc: discoveryClient,
|
||||
dryRunBuff: &bytes.Buffer{},
|
||||
registries: registries,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&i)
|
||||
@@ -1042,16 +1045,41 @@ func (h *Installer) installDependency(addon *InstallPackage) error {
|
||||
if h.dryRun {
|
||||
continue
|
||||
}
|
||||
// always install addon's latest version
|
||||
depAddon, err := h.loadInstallPackage(dep.Name, dep.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
depHandler := *h
|
||||
depHandler.args = nil
|
||||
if err = depHandler.enableAddon(depAddon); err != nil {
|
||||
return errors.Wrap(err, "fail to dispatch dependent addon resource")
|
||||
var depAddon *InstallPackage
|
||||
// try to install the dependent addon from the same registry with the current addon
|
||||
depAddon, err = h.loadInstallPackage(dep.Name, dep.Version)
|
||||
if err == nil {
|
||||
if err = depHandler.enableAddon(depAddon); err != nil {
|
||||
return errors.Wrap(err, "fail to dispatch dependent addon resource")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !errors.Is(err, ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
for _, registry := range h.registries {
|
||||
// try to install dependent addon from other registries
|
||||
depHandler.r = &Registry{
|
||||
Name: registry.Name, Helm: registry.Helm, OSS: registry.OSS, Git: registry.Git, Gitee: registry.Gitee, Gitlab: registry.Gitlab,
|
||||
}
|
||||
depAddon, err = depHandler.loadInstallPackage(dep.Name, dep.Version)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if errors.Is(err, ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
if err = depHandler.enableAddon(depAddon); err != nil {
|
||||
return errors.Wrap(err, "fail to dispatch dependent addon resource")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("dependency addon: %s with version: %s cannot be found from all registries", dep.Name, dep.Version)
|
||||
}
|
||||
if h.dryRun && len(dependencies) > 0 {
|
||||
klog.Warningf("dry run addon won't install dependencies, please make sure your system has already installed these addons: %v", strings.Join(dependencies, ", "))
|
||||
|
||||
@@ -355,7 +355,7 @@ var _ = Describe("func addon update ", func() {
|
||||
}, time.Millisecond*500, 30*time.Second).Should(BeNil())
|
||||
|
||||
pkg := &InstallPackage{Meta: Meta{Name: "test-update", Version: "1.3.0"}}
|
||||
h := NewAddonInstaller(context.Background(), k8sClient, nil, nil, nil, &Registry{Name: "test"}, nil, nil)
|
||||
h := NewAddonInstaller(context.Background(), k8sClient, nil, nil, nil, &Registry{Name: "test"}, nil, nil, nil)
|
||||
h.addon = pkg
|
||||
Expect(h.dispatchAddonResource(pkg)).Should(BeNil())
|
||||
|
||||
@@ -418,7 +418,7 @@ var _ = Describe("test dry-run addon from local dir", func() {
|
||||
pkg, err := GetInstallPackageFromReader(r, &meta, UIData)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
h := NewAddonInstaller(ctx, k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, &Registry{Name: LocalAddonRegistryName}, map[string]interface{}{"example": "test-dry-run"}, nil, DryRunAddon)
|
||||
h := NewAddonInstaller(ctx, k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, &Registry{Name: LocalAddonRegistryName}, map[string]interface{}{"example": "test-dry-run"}, nil, nil, DryRunAddon)
|
||||
|
||||
err = h.enableAddon(pkg)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -55,8 +55,8 @@ const (
|
||||
)
|
||||
|
||||
// EnableAddon will enable addon with dependency check, source is where addon from.
|
||||
func EnableAddon(ctx context.Context, name string, version string, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache, opts ...InstallOption) error {
|
||||
h := NewAddonInstaller(ctx, cli, discoveryClient, apply, config, &r, args, cache, opts...)
|
||||
func EnableAddon(ctx context.Context, name string, version string, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache, registries []Registry, opts ...InstallOption) error {
|
||||
h := NewAddonInstaller(ctx, cli, discoveryClient, apply, config, &r, args, cache, registries, opts...)
|
||||
pkg, err := h.loadInstallPackage(name, version)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -113,7 +113,7 @@ func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli cli
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := NewAddonInstaller(ctx, cli, dc, applicator, config, &Registry{Name: LocalAddonRegistryName}, args, nil, opts...)
|
||||
h := NewAddonInstaller(ctx, cli, dc, applicator, config, &Registry{Name: LocalAddonRegistryName}, args, nil, nil, opts...)
|
||||
needEnableAddonNames, err := h.checkDependency(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -187,7 +187,7 @@ func findLegacyAddonDefs(ctx context.Context, k8sClient client.Client, addonName
|
||||
if registry.Name == registryName {
|
||||
var uiData *UIData
|
||||
if !IsVersionRegistry(registry) {
|
||||
installer := NewAddonInstaller(ctx, k8sClient, nil, nil, config, ®istries[i], nil, nil)
|
||||
installer := NewAddonInstaller(ctx, k8sClient, nil, nil, config, ®istries[i], nil, nil, nil)
|
||||
metas, err := installer.getAddonMeta()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -502,3 +502,17 @@ func checkBondComponentExist(u unstructured.Unstructured, app v1beta1.Applicatio
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FilterDependencyRegistries will return all registries besides the target registry itself
|
||||
func FilterDependencyRegistries(i int, rs []Registry) []Registry {
|
||||
if i >= len(rs) {
|
||||
return rs
|
||||
}
|
||||
if i < 0 {
|
||||
return rs
|
||||
}
|
||||
ret := make([]Registry, len(rs)-1)
|
||||
copy(ret, rs[:i])
|
||||
copy(ret[i:], rs[i+1:])
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -329,6 +329,57 @@ func TestCheckObjectBindingComponent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterDependencyRegistries(t *testing.T) {
|
||||
testCases := []struct {
|
||||
registries []Registry
|
||||
index int
|
||||
res []Registry
|
||||
origin []Registry
|
||||
}{
|
||||
{
|
||||
registries: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
index: 0,
|
||||
res: []Registry{{Name: "r2"}, {Name: "r3"}},
|
||||
origin: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
},
|
||||
{
|
||||
registries: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
index: 1,
|
||||
res: []Registry{{Name: "r1"}, {Name: "r3"}},
|
||||
origin: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
},
|
||||
{
|
||||
registries: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
index: 2,
|
||||
res: []Registry{{Name: "r1"}, {Name: "r2"}},
|
||||
origin: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
},
|
||||
{
|
||||
registries: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
index: 3,
|
||||
res: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
origin: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
},
|
||||
{
|
||||
registries: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
index: -1,
|
||||
res: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
origin: []Registry{{Name: "r1"}, {Name: "r2"}, {Name: "r3"}},
|
||||
},
|
||||
{
|
||||
registries: []Registry{},
|
||||
index: 0,
|
||||
res: []Registry{},
|
||||
origin: []Registry{},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
res := FilterDependencyRegistries(testCase.index, testCase.registries)
|
||||
assert.Equal(t, res, testCase.res)
|
||||
assert.Equal(t, testCase.registries, testCase.origin)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
compDefYaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
|
||||
@@ -386,6 +386,7 @@ type ApplicationTrigger struct {
|
||||
Type string `json:"type"`
|
||||
PayloadType string `json:"payloadType"`
|
||||
ComponentName string `json:"componentName"`
|
||||
Registry string `json:"registry,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -400,8 +400,22 @@ func (u *addonServiceImpl) EnableAddon(ctx context.Context, name string, args ap
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range registries {
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
|
||||
if len(args.RegistryName) != 0 {
|
||||
foundRegistry := false
|
||||
for _, registry := range registries {
|
||||
if registry.Name == args.RegistryName {
|
||||
foundRegistry = true
|
||||
}
|
||||
}
|
||||
if !foundRegistry {
|
||||
return bcode.ErrAddonRegistryNotExist.SetMessage(fmt.Sprintf("specified registry %s not exist", args.RegistryName))
|
||||
}
|
||||
}
|
||||
for i, r := range registries {
|
||||
if len(args.RegistryName) != 0 && args.RegistryName != r.Name {
|
||||
continue
|
||||
}
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -471,8 +485,8 @@ func (u *addonServiceImpl) UpdateAddon(ctx context.Context, name string, args ap
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range registries {
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
|
||||
for i, r := range registries {
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -418,6 +418,7 @@ func (c *applicationServiceImpl) CreateApplicationTrigger(ctx context.Context, a
|
||||
Type: req.Type,
|
||||
PayloadType: req.PayloadType,
|
||||
ComponentName: req.ComponentName,
|
||||
Registry: req.Registry,
|
||||
Token: genWebhookToken(),
|
||||
}
|
||||
if err := c.Store.Add(ctx, trigger); err != nil {
|
||||
|
||||
@@ -215,13 +215,16 @@ func (c *customHandlerImpl) install() {
|
||||
}
|
||||
|
||||
func (c *acrHandlerImpl) handle(ctx context.Context, webhookTrigger *model.ApplicationTrigger, app *model.Application) (interface{}, error) {
|
||||
|
||||
component, err := getComponent(ctx, c.w.Store, webhookTrigger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acrReq := c.req
|
||||
image := fmt.Sprintf("registry.%s.aliyuncs.com/%s:%s", acrReq.Repository.Region, acrReq.Repository.RepoFullName, acrReq.PushData.Tag)
|
||||
registry := webhookTrigger.Registry
|
||||
if registry == "" {
|
||||
registry = fmt.Sprintf("registry.%s.aliyuncs.com", acrReq.Repository.Region)
|
||||
}
|
||||
image := fmt.Sprintf("%s/%s:%s", registry, acrReq.Repository.RepoFullName, acrReq.PushData.Tag)
|
||||
if err := c.w.patchComponentProperties(ctx, component, &runtime.RawExtension{
|
||||
Raw: []byte(fmt.Sprintf(`{"image": "%s"}`, image)),
|
||||
}); err != nil {
|
||||
|
||||
@@ -196,6 +196,40 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect((*comp.Properties)["image"]).Should(Equal("registry.test-region.aliyuncs.com/test-namespace/test-repo:test-tag"))
|
||||
|
||||
By("Test HandleApplicationWebhook function with ACR payload and registry info")
|
||||
acrTrigger, err = appService.CreateApplicationTrigger(context.TODO(), appModel, apisv1.CreateApplicationTriggerRequest{
|
||||
Name: "test-acr",
|
||||
PayloadType: "acr",
|
||||
Type: "webhook",
|
||||
ComponentName: "component-name-webhook",
|
||||
Registry: "test-enterprise-registry.test-region.cr.aliyuncs.com",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
acrBody = apisv1.HandleApplicationTriggerACRRequest{
|
||||
PushData: apisv1.ACRPushData{
|
||||
Digest: "test-digest",
|
||||
Tag: "test-tag",
|
||||
},
|
||||
Repository: apisv1.ACRRepository{
|
||||
Name: "test-repo",
|
||||
Namespace: "test-namespace",
|
||||
Region: "test-region",
|
||||
RepoFullName: "test-namespace/test-repo",
|
||||
RepoType: "public",
|
||||
},
|
||||
}
|
||||
body, err = json.Marshal(acrBody)
|
||||
Expect(err).Should(BeNil())
|
||||
httpreq, err = http.NewRequest("post", "/", bytes.NewBuffer(body))
|
||||
httpreq.Header.Add(restful.HEADER_ContentType, "application/json")
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = webhookService.HandleApplicationWebhook(context.TODO(), acrTrigger.Token, restful.NewRequest(httpreq))
|
||||
Expect(err).Should(BeNil())
|
||||
comp, err = appService.GetApplicationComponent(context.TODO(), appModel, "component-name-webhook")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect((*comp.Properties)["image"]).Should(Equal("test-enterprise-registry.test-region.cr.aliyuncs.com/test-namespace/test-repo:test-tag"))
|
||||
|
||||
By("Test HandleApplicationWebhook function with harbor payload")
|
||||
harborTrigger, err := appService.CreateApplicationTrigger(context.TODO(), appModel, apisv1.CreateApplicationTriggerRequest{
|
||||
Name: "test-harbor",
|
||||
|
||||
@@ -129,6 +129,8 @@ type EnableAddonRequest struct {
|
||||
Clusters []string `json:"clusters,omitempty"`
|
||||
// Version specify the version of addon to enable
|
||||
Version string `json:"version,omitempty"`
|
||||
// RegistryName specify the registry name
|
||||
RegistryName string `json:"registryName,omitempty"`
|
||||
}
|
||||
|
||||
// ListAddonResponse defines the format for addon list response
|
||||
@@ -504,6 +506,7 @@ type CreateApplicationTriggerRequest struct {
|
||||
Type string `json:"type" validate:"oneof=webhook"`
|
||||
PayloadType string `json:"payloadType" validate:"checkpayloadtype"`
|
||||
ComponentName string `json:"componentName,omitempty" optional:"true"`
|
||||
Registry string `json:"registry,omitempty" optional:"true"`
|
||||
}
|
||||
|
||||
// ApplicationTriggerBase application trigger base model
|
||||
|
||||
@@ -73,6 +73,9 @@ var (
|
||||
|
||||
// ErrCloudShellNotInit means the cloudshell CR not created
|
||||
ErrCloudShellNotInit = NewBcode(400, 50021, "Closing the console window and retry")
|
||||
|
||||
// ErrRegistryNotExist means the specified registry not exist
|
||||
ErrRegistryNotExist = NewBcode(400, 50022, "The specified not exist")
|
||||
)
|
||||
|
||||
// isGithubRateLimit check if error is github rate limit
|
||||
|
||||
@@ -19,6 +19,7 @@ package component
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -141,10 +142,18 @@ func SelectRefObjectsForDispatch(ctx context.Context, cli client.Client, appNs s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isNamespaced, err := IsGroupVersionKindNamespaceScoped(cli.RESTMapper(), gvk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if selector.Name == "" && labelSelector != nil {
|
||||
uns := &unstructured.UnstructuredList{}
|
||||
uns.SetGroupVersionKind(gvk)
|
||||
if err = cli.List(ctx, uns, client.InNamespace(ns), client.MatchingLabels(labelSelector)); err != nil {
|
||||
opts := []client.ListOption{client.MatchingLabels(labelSelector)}
|
||||
if isNamespaced {
|
||||
opts = append(opts, client.InNamespace(ns))
|
||||
}
|
||||
if err = cli.List(ctx, uns, opts...); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to load ref object %s with selector", gvk.Kind)
|
||||
}
|
||||
for _, _un := range uns.Items {
|
||||
@@ -154,7 +163,9 @@ func SelectRefObjectsForDispatch(ctx context.Context, cli client.Client, appNs s
|
||||
un := &unstructured.Unstructured{}
|
||||
un.SetGroupVersionKind(gvk)
|
||||
un.SetName(selector.Name)
|
||||
un.SetNamespace(ns)
|
||||
if isNamespaced {
|
||||
un.SetNamespace(ns)
|
||||
}
|
||||
if selector.Name == "" {
|
||||
un.SetName(compName)
|
||||
}
|
||||
@@ -248,3 +259,15 @@ func ConvertUnstructuredsToReferredObjects(uns []*unstructured.Unstructured) (re
|
||||
}
|
||||
return refObjs, nil
|
||||
}
|
||||
|
||||
// IsGroupVersionKindNamespaceScoped check if the target GroupVersionKind is namespace scoped resource
|
||||
func IsGroupVersionKindNamespaceScoped(mapper meta.RESTMapper, gvk schema.GroupVersionKind) (bool, error) {
|
||||
mappings, err := mapper.RESTMappings(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(mappings) == 0 {
|
||||
return false, fmt.Errorf("unable to fund the mappings for gvk %s", gvk)
|
||||
}
|
||||
return mappings[0].Scope.Name() == meta.RESTScopeNameNamespace, nil
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
@@ -111,6 +112,10 @@ var _ = Describe("Test ref-objects functions", func() {
|
||||
Namespace: "test",
|
||||
Labels: map[string]string{"key": "value"},
|
||||
},
|
||||
}, &rbacv1.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-cluster-role",
|
||||
},
|
||||
}} {
|
||||
Expect(k8sClient.Create(context.Background(), obj)).Should(Succeed())
|
||||
}
|
||||
@@ -119,25 +124,26 @@ var _ = Describe("Test ref-objects functions", func() {
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": apiVersion,
|
||||
"kind": kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
"namespace": namespace,
|
||||
},
|
||||
"metadata": map[string]interface{}{"name": name},
|
||||
},
|
||||
}
|
||||
if namespace != "" {
|
||||
un.SetNamespace(namespace)
|
||||
}
|
||||
if labels != nil {
|
||||
un.Object["metadata"].(map[string]interface{})["labels"] = labels
|
||||
}
|
||||
return un
|
||||
}
|
||||
testcases := map[string]struct {
|
||||
Input v1alpha1.ObjectReferrer
|
||||
compName string
|
||||
appNs string
|
||||
Output []*unstructured.Unstructured
|
||||
Error string
|
||||
Scope string
|
||||
IsService bool
|
||||
Input v1alpha1.ObjectReferrer
|
||||
compName string
|
||||
appNs string
|
||||
Output []*unstructured.Unstructured
|
||||
Error string
|
||||
Scope string
|
||||
IsService bool
|
||||
IsClusterRole bool
|
||||
}{
|
||||
"normal": {
|
||||
Input: v1alpha1.ObjectReferrer{
|
||||
@@ -259,6 +265,16 @@ var _ = Describe("Test ref-objects functions", func() {
|
||||
Scope: RefObjectsAvailableScopeCluster,
|
||||
Error: "cannot refer to objects outside control plane",
|
||||
},
|
||||
"test-cluster-scope-resource": {
|
||||
Input: v1alpha1.ObjectReferrer{
|
||||
ObjectTypeIdentifier: v1alpha1.ObjectTypeIdentifier{Resource: "clusterrole"},
|
||||
ObjectSelector: v1alpha1.ObjectSelector{Name: "test-cluster-role"},
|
||||
},
|
||||
appNs: "test",
|
||||
Scope: RefObjectsAvailableScopeCluster,
|
||||
Output: []*unstructured.Unstructured{createUnstructured("rbac.authorization.k8s.io/v1", "ClusterRole", "test-cluster-role", "", nil)},
|
||||
IsClusterRole: true,
|
||||
},
|
||||
}
|
||||
for name, tt := range testcases {
|
||||
By("Test " + name)
|
||||
@@ -276,6 +292,9 @@ var _ = Describe("Test ref-objects functions", func() {
|
||||
Expect(output[0].Object["kind"]).Should(Equal("Service"))
|
||||
Expect(output[0].Object["spec"].(map[string]interface{})["clusterIP"]).Should(BeNil())
|
||||
} else {
|
||||
if tt.IsClusterRole {
|
||||
delete(output[0].Object, "rules")
|
||||
}
|
||||
Expect(output).Should(Equal(tt.Output))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,10 +365,9 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
|
||||
for _, auxiliary := range auxiliaries {
|
||||
target := outputsPatcher.LookupPath(value.FieldPath(auxiliary.Name))
|
||||
if !target.Exists() {
|
||||
return errors.WithMessagef(err, "trait=%s, to=%s, invalid patch trait into auxiliary workload", td.name, auxiliary.Name)
|
||||
continue
|
||||
}
|
||||
patcher := outputsPatcher.LookupPath(value.FieldPath(auxiliary.Name))
|
||||
if err := auxiliary.Ins.Unify(patcher); err != nil {
|
||||
if err = auxiliary.Ins.Unify(target); err != nil {
|
||||
return errors.WithMessagef(err, "trait=%s, to=%s, invalid patch trait into auxiliary workload", td.name, auxiliary.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1480,3 +1480,57 @@ if len(context.outputs.ingress.status.loadBalancer.ingress) == 0 {
|
||||
assert.Equal(t, ca.expMessage, gotMessage, message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTraitPatchSingleOutput(t *testing.T) {
|
||||
baseTemplate := `
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: selector: matchLabels: "app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: name: context.name + "game-config"
|
||||
data: {}
|
||||
}
|
||||
|
||||
outputs: sideconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: name: context.name + "side-config"
|
||||
data: {}
|
||||
}
|
||||
|
||||
parameter: {}
|
||||
`
|
||||
traitTemplate := `
|
||||
patchOutputs: sideconfig: data: key: "val"
|
||||
parameter: {}
|
||||
`
|
||||
ctx := process.NewContext(process.ContextData{
|
||||
AppName: "myapp",
|
||||
CompName: "test",
|
||||
Namespace: "default",
|
||||
AppRevisionName: "myapp-v1",
|
||||
})
|
||||
wt := NewWorkloadAbstractEngine("-", &packages.PackageDiscover{})
|
||||
if err := wt.Complete(ctx, baseTemplate, map[string]interface{}{}); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
td := NewTraitAbstractEngine("single-patch", &packages.PackageDiscover{})
|
||||
r := require.New(t)
|
||||
err := td.Complete(ctx, traitTemplate, map[string]string{})
|
||||
r.NoError(err)
|
||||
base, assists := ctx.Output()
|
||||
r.NotNil(base)
|
||||
r.Equal(2, len(assists))
|
||||
got, err := assists[1].Ins.Unstructured()
|
||||
r.NoError(err)
|
||||
val, ok, err := unstructured.NestedString(got.Object, "data", "key")
|
||||
r.NoError(err)
|
||||
r.True(ok)
|
||||
r.Equal("val", val)
|
||||
}
|
||||
|
||||
4
pkg/utils/env/env_test.go
vendored
4
pkg/utils/env/env_test.go
vendored
@@ -51,6 +51,9 @@ func TestCreateEnv(t *testing.T) {
|
||||
var err error
|
||||
cfg, err = testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
assert.NoError(t, clientgoscheme.AddToScheme(testScheme))
|
||||
|
||||
rawClient, err = client.New(cfg, client.Options{Scheme: testScheme})
|
||||
@@ -95,4 +98,5 @@ func TestCreateEnv(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -148,6 +148,8 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
vela addon enable <your-local-addon-path>
|
||||
Enable addon with specified args (the args should be defined in addon's parameters):
|
||||
vela addon enable <addon-name> <my-parameter-of-addon>=<my-value>
|
||||
Enable addon with specified registry:
|
||||
vela addon enable <registryName>/<addonName>
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
@@ -543,10 +545,27 @@ func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.Dis
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, registry := range registries {
|
||||
registryName, addonName, err := splitSpecifyRegistry(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(registryName) != 0 {
|
||||
foundRegistry := false
|
||||
for _, registry := range registries {
|
||||
if registry.Name == registryName {
|
||||
foundRegistry = true
|
||||
}
|
||||
}
|
||||
if !foundRegistry {
|
||||
return fmt.Errorf("specified registry %s not exist", registryName)
|
||||
}
|
||||
}
|
||||
for i, registry := range registries {
|
||||
opts := addonOptions()
|
||||
err = pkgaddon.EnableAddon(ctx, name, version, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, opts...)
|
||||
if len(registryName) != 0 && registryName != registry.Name {
|
||||
continue
|
||||
}
|
||||
err = pkgaddon.EnableAddon(ctx, addonName, version, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries), opts...)
|
||||
if errors.Is(err, pkgaddon.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
@@ -558,21 +577,24 @@ func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.Dis
|
||||
}
|
||||
input := NewUserInput()
|
||||
if input.AskBool(unMatchErr.Error(), &UserInputOptions{AssumeYes: false}) {
|
||||
err = pkgaddon.EnableAddon(ctx, name, availableVersion, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil)
|
||||
err = pkgaddon.EnableAddon(ctx, addonName, availableVersion, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
return err
|
||||
}
|
||||
// The user does not agree to use the version provided by us
|
||||
return fmt.Errorf("you can try another version by command: \"vela addon enable %s --version <version> \" ", name)
|
||||
return fmt.Errorf("you can try another version by command: \"vela addon enable %s --version <version> \" ", addonName)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = waitApplicationRunning(k8sClient, name); err != nil {
|
||||
if err = waitApplicationRunning(k8sClient, addonName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("addon: %s not found in registries", name)
|
||||
if len(registryName) != 0 {
|
||||
return fmt.Errorf("addon: %s not found in registry %s", addonName, registryName)
|
||||
}
|
||||
return fmt.Errorf("addon: %s not found in all candidate registries", addonName)
|
||||
}
|
||||
|
||||
func addonOptions() []pkgaddon.InstallOption {
|
||||
@@ -1136,3 +1158,15 @@ func NewAddonPackageCommand(c common.Args) *cobra.Command {
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func splitSpecifyRegistry(name string) (string, string, error) {
|
||||
res := strings.Split(name, "/")
|
||||
switch len(res) {
|
||||
case 2:
|
||||
return res[0], res[1], nil
|
||||
case 1:
|
||||
return "", res[0], nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("invalid addon name, you should specify name only <addonName> or with registry as prefix <registryName>/<addonName>")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,3 +443,37 @@ func TestNewAddonCreateCommand(t *testing.T) {
|
||||
_ = os.RemoveAll("test-addon")
|
||||
|
||||
}
|
||||
|
||||
func TestCheckSpecifyRegistry(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registry string
|
||||
addonName string
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "fluxcd",
|
||||
registry: "",
|
||||
addonName: "fluxcd",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "kubevela/fluxcd",
|
||||
registry: "kubevela",
|
||||
addonName: "fluxcd",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "test/kubevela/fluxcd",
|
||||
registry: "",
|
||||
addonName: "",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
r, n, err := splitSpecifyRegistry(testCase.name)
|
||||
assert.Equal(t, err != nil, testCase.hasError)
|
||||
assert.Equal(t, r, testCase.registry)
|
||||
assert.Equal(t, n, testCase.addonName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ func TestInfo(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
info := NewInfo()
|
||||
info.Init(cfg)
|
||||
assert.Equal(t, info.GetColumnCount(), 7)
|
||||
|
||||
@@ -38,6 +38,9 @@ func TestApp(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -38,6 +38,10 @@ func TestTopologyView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestApplicationView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -38,6 +38,10 @@ func TestClusterNamespaceView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
@@ -83,4 +87,5 @@ func TestClusterNamespaceView(t *testing.T) {
|
||||
cnsView.Table.Table = cnsView.Table.Select(1, 1)
|
||||
assert.Empty(t, cnsView.managedResourceView(nil))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestClusterView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestContainerView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -36,6 +36,10 @@ func TestHelpView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestLogView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestManagedResourceView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestNamespaceView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -36,6 +36,10 @@ func TestPageStack(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -39,6 +39,10 @@ func TestPodView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
@@ -38,6 +38,10 @@ func TestYamlView(t *testing.T) {
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, testEnv.Stop())
|
||||
}()
|
||||
|
||||
testClient, err := client.New(cfg, client.Options{Scheme: common.Scheme})
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
|
||||
23
references/docgen/def-doc/policy/health.eg.md
Normal file
23
references/docgen/def-doc/policy/health.eg.md
Normal file
@@ -0,0 +1,23 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: example-app-rollout
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
ports:
|
||||
- port: 8000
|
||||
expose: true
|
||||
type: webservice
|
||||
policies:
|
||||
- name: health-policy-demo
|
||||
type: health
|
||||
properties:
|
||||
probeInterval: 5
|
||||
probeTimeout: 10
|
||||
```
|
||||
29
references/docgen/def-doc/trait/affinity.eg.md
Normal file
29
references/docgen/def-doc/trait/affinity.eg.md
Normal file
@@ -0,0 +1,29 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: busybox
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: webservice
|
||||
properties:
|
||||
image: busybox
|
||||
cmd: ["sleep", "86400"]
|
||||
labels:
|
||||
label-key: label-value
|
||||
to-delete-label-key: to-delete-label-value
|
||||
traits:
|
||||
- type: affinity
|
||||
properties:
|
||||
podAffinity:
|
||||
preferred:
|
||||
- weight: 1
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: "secrity"
|
||||
values: ["S1"]
|
||||
namespaces: ["default"]
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
```
|
||||
41
references/docgen/def-doc/trait/json-merge-patch.eg.md
Normal file
41
references/docgen/def-doc/trait/json-merge-patch.eg.md
Normal file
@@ -0,0 +1,41 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: busybox
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: webservice
|
||||
properties:
|
||||
image: busybox
|
||||
cmd: ["sleep", "86400"]
|
||||
labels:
|
||||
pod-label-key: pod-label-value
|
||||
to-delete-label-key: to-delete-label-value
|
||||
traits:
|
||||
# the json merge patch can be used to add, replace and delete fields
|
||||
# the following part will
|
||||
# 1. add `deploy-label-key` to deployment labels
|
||||
# 2. set deployment replicas to 3
|
||||
# 3. set `pod-label-key` to `pod-label-modified-value` in pod labels
|
||||
# 4. delete `to-delete-label-key` in pod labels
|
||||
# 5. reset `containers` for pod
|
||||
- type: json-merge-patch
|
||||
properties:
|
||||
metadata:
|
||||
labels:
|
||||
deploy-label-key: deploy-label-added-value
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
pod-label-key: pod-label-modified-value
|
||||
to-delete-label-key: null
|
||||
spec:
|
||||
containers:
|
||||
- name: busybox-new
|
||||
image: busybox:1.34
|
||||
command: ["sleep", "864000"]
|
||||
```
|
||||
41
references/docgen/def-doc/trait/json-patch.eg.md
Normal file
41
references/docgen/def-doc/trait/json-patch.eg.md
Normal file
@@ -0,0 +1,41 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: busybox
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: webservice
|
||||
properties:
|
||||
image: busybox
|
||||
cmd: ["sleep", "86400"]
|
||||
labels:
|
||||
pod-label-key: pod-label-value
|
||||
to-delete-label-key: to-delete-label-value
|
||||
traits:
|
||||
# the json patch can be used to add, replace and delete fields
|
||||
# the following part will
|
||||
# 1. add `deploy-label-key` to deployment labels
|
||||
# 2. set deployment replicas to 3
|
||||
# 3. set `pod-label-key` to `pod-label-modified-value` in pod labels
|
||||
# 4. delete `to-delete-label-key` in pod labels
|
||||
# 5. add sidecar container for pod
|
||||
- type: json-patch
|
||||
properties:
|
||||
operations:
|
||||
- op: add
|
||||
path: "/spec/replicas"
|
||||
value: 3
|
||||
- op: replace
|
||||
path: "/spec/template/metadata/labels/pod-label-key"
|
||||
value: pod-label-modified-value
|
||||
- op: remove
|
||||
path: "/spec/template/metadata/labels/to-delete-label-key"
|
||||
- op: add
|
||||
path: "/spec/template/spec/containers/1"
|
||||
value:
|
||||
name: busybox-sidecar
|
||||
image: busybox:1.34
|
||||
command: ["sleep", "864000"]
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: application-with-topologyspreadconstraints
|
||||
spec:
|
||||
components:
|
||||
- name: busybox-runner
|
||||
type: worker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- sleep
|
||||
- '1000'
|
||||
traits:
|
||||
- type: topologyspreadconstraints
|
||||
properties:
|
||||
constraints:
|
||||
- topologyKey: zone
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
zone: us-east-1a
|
||||
maxSkew: 1
|
||||
whenUnsatisfiable: DoNotSchedule
|
||||
minDomains: 1
|
||||
nodeAffinityPolicy: Ignore
|
||||
nodeTaintsPolicy: Ignore
|
||||
- topologyKey: node
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: foo
|
||||
operator: In
|
||||
values:
|
||||
- abc
|
||||
maxSkew: 1
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
minDomains: 1
|
||||
nodeAffinityPolicy: Ignore
|
||||
nodeTaintsPolicy: Ignore
|
||||
```
|
||||
32
references/docgen/def-doc/workflowstep/create-config.eg.md
Normal file
32
references/docgen/def-doc/workflowstep/create-config.eg.md
Normal file
@@ -0,0 +1,32 @@
|
||||
```yaml
|
||||
kind: Application
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
metadata:
|
||||
name: test-config
|
||||
namespace: "config-e2e-test"
|
||||
spec:
|
||||
components: []
|
||||
workflow:
|
||||
steps:
|
||||
- name: write-config
|
||||
type: create-config
|
||||
properties:
|
||||
name: test
|
||||
config:
|
||||
key1: value1
|
||||
key2: 2
|
||||
key3: true
|
||||
key4:
|
||||
key5: value5
|
||||
- name: read-config
|
||||
type: read-config
|
||||
properties:
|
||||
name: test
|
||||
outputs:
|
||||
- fromKey: config
|
||||
name: read-config
|
||||
- name: delete-config
|
||||
type: delete-config
|
||||
properties:
|
||||
name: test
|
||||
```
|
||||
25
references/docgen/def-doc/workflowstep/delete-config.eg.md
Normal file
25
references/docgen/def-doc/workflowstep/delete-config.eg.md
Normal file
@@ -0,0 +1,25 @@
|
||||
```yaml
|
||||
kind: Application
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
metadata:
|
||||
name: test-config
|
||||
namespace: "config-e2e-test"
|
||||
spec:
|
||||
components: []
|
||||
workflow:
|
||||
steps:
|
||||
- name: write-config
|
||||
type: create-config
|
||||
properties:
|
||||
name: test
|
||||
config:
|
||||
key1: value1
|
||||
key2: 2
|
||||
key3: true
|
||||
key4:
|
||||
key5: value5
|
||||
- name: delete-config
|
||||
type: delete-config
|
||||
properties:
|
||||
name: test
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: rds-app
|
||||
namespace: project-1
|
||||
spec:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
instance_name: db
|
||||
account_name: kubevela
|
||||
password: my-password
|
||||
writeConnectionSecretToRef:
|
||||
name: project-1-rds-conn-credential
|
||||
policies:
|
||||
- name: env-policy
|
||||
type: env-binding
|
||||
properties:
|
||||
envs:
|
||||
# 部署 RDS 给杭州集群
|
||||
- name: hangzhou
|
||||
placement:
|
||||
clusterSelector:
|
||||
name: cluster-hangzhou
|
||||
patch:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
# region: hangzhou
|
||||
instance_name: hangzhou_db
|
||||
# 部署 RDS 给香港集群
|
||||
- name: hongkong
|
||||
placement:
|
||||
clusterSelector:
|
||||
name: cluster-hongkong
|
||||
namespaceSelector:
|
||||
name: hk-project-1
|
||||
patch:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
# region: hongkong
|
||||
instance_name: hongkong_db
|
||||
writeConnectionSecretToRef:
|
||||
name: hk-project-rds-credential
|
||||
|
||||
workflow:
|
||||
steps:
|
||||
# 部署 RDS 给杭州区用
|
||||
- name: deploy-hangzhou-rds
|
||||
type: deploy-cloud-resource
|
||||
properties:
|
||||
env: hangzhou
|
||||
# 将给杭州区用的 RDS 共享给北京区
|
||||
- name: share-hangzhou-rds-to-beijing
|
||||
type: share-cloud-resource
|
||||
properties:
|
||||
env: hangzhou
|
||||
placements:
|
||||
- cluster: cluster-beijing
|
||||
# 部署 RDS 给香港区用
|
||||
- name: deploy-hongkong-rds
|
||||
type: deploy-cloud-resource
|
||||
properties:
|
||||
env: hongkong
|
||||
# 将给香港区用的 RDS 共享给香港区其他项目用
|
||||
- name: share-hongkong-rds-to-other-namespace
|
||||
type: share-cloud-resource
|
||||
properties:
|
||||
env: hongkong
|
||||
placements:
|
||||
- cluster: cluster-hongkong
|
||||
namespace: hk-project-2
|
||||
- cluster: cluster-hongkong
|
||||
namespace: hk-project-3
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: jdbc
|
||||
spec:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
instance_name: favorite-links
|
||||
database_name: db1
|
||||
account_name: oamtest
|
||||
password: U34rfwefwefffaked
|
||||
security_ips: [ "0.0.0.0/0" ]
|
||||
privilege: ReadWrite
|
||||
writeConnectionSecretToRef:
|
||||
name: db-conn
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
|
||||
workflow:
|
||||
steps:
|
||||
- name: jdbc
|
||||
type: generate-jdbc-connection
|
||||
outputs:
|
||||
- name: jdbc
|
||||
valueFrom: jdbc
|
||||
properties:
|
||||
name: db-conn
|
||||
namespace: default
|
||||
- name: apply
|
||||
type: apply-component
|
||||
inputs:
|
||||
- from: jdbc
|
||||
parameterKey: env
|
||||
properties:
|
||||
component: express-server
|
||||
```
|
||||
50
references/docgen/def-doc/workflowstep/list-config.eg.md
Normal file
50
references/docgen/def-doc/workflowstep/list-config.eg.md
Normal file
@@ -0,0 +1,50 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha1
|
||||
kind: WorkflowRun
|
||||
metadata:
|
||||
name: observability
|
||||
namespace: vela-system
|
||||
spec:
|
||||
context:
|
||||
readConfig: true
|
||||
mode:
|
||||
workflowSpec:
|
||||
steps:
|
||||
- name: Enable Prism
|
||||
type: addon-operation
|
||||
properties:
|
||||
addonName: vela-prism
|
||||
|
||||
- name: Enable o11y
|
||||
type: addon-operation
|
||||
properties:
|
||||
addonName: o11y-definitions
|
||||
operation: enable
|
||||
args:
|
||||
- --override-definitions
|
||||
|
||||
- name: Prepare Prometheus
|
||||
type: step-group
|
||||
subSteps:
|
||||
- name: get-exist-prometheus
|
||||
type: list-config
|
||||
properties:
|
||||
template: prometheus-server
|
||||
outputs:
|
||||
- name: prometheus
|
||||
valueFrom: "output.configs"
|
||||
|
||||
- name: prometheus-server
|
||||
inputs:
|
||||
- from: prometheus
|
||||
# TODO: Make it is not required
|
||||
parameterKey: configs
|
||||
if: "!context.readConfig || len(inputs.prometheus) == 0"
|
||||
type: addon-operation
|
||||
properties:
|
||||
addonName: prometheus-server
|
||||
operation: enable
|
||||
args:
|
||||
- memory=4096Mi
|
||||
- serviceType=LoadBalancer
|
||||
```
|
||||
18
references/docgen/def-doc/workflowstep/read-config.eg.md
Normal file
18
references/docgen/def-doc/workflowstep/read-config.eg.md
Normal file
@@ -0,0 +1,18 @@
|
||||
```yaml
|
||||
kind: Application
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
metadata:
|
||||
name: test-config
|
||||
namespace: "config-e2e-test"
|
||||
spec:
|
||||
components: []
|
||||
workflow:
|
||||
steps:
|
||||
- name: read-config
|
||||
type: read-config
|
||||
properties:
|
||||
name: test
|
||||
outputs:
|
||||
- fromKey: config
|
||||
name: read-config
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: rds-app
|
||||
namespace: project-1
|
||||
spec:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
instance_name: db
|
||||
account_name: kubevela
|
||||
password: my-password
|
||||
writeConnectionSecretToRef:
|
||||
name: project-1-rds-conn-credential
|
||||
policies:
|
||||
- name: env-policy
|
||||
type: env-binding
|
||||
properties:
|
||||
envs:
|
||||
# 部署 RDS 给杭州集群
|
||||
- name: hangzhou
|
||||
placement:
|
||||
clusterSelector:
|
||||
name: cluster-hangzhou
|
||||
patch:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
# region: hangzhou
|
||||
instance_name: hangzhou_db
|
||||
# 部署 RDS 给香港集群
|
||||
- name: hongkong
|
||||
placement:
|
||||
clusterSelector:
|
||||
name: cluster-hongkong
|
||||
namespaceSelector:
|
||||
name: hk-project-1
|
||||
patch:
|
||||
components:
|
||||
- name: db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
# region: hongkong
|
||||
instance_name: hongkong_db
|
||||
writeConnectionSecretToRef:
|
||||
name: hk-project-rds-credential
|
||||
|
||||
workflow:
|
||||
steps:
|
||||
# 部署 RDS 给杭州区用
|
||||
- name: deploy-hangzhou-rds
|
||||
type: deploy-cloud-resource
|
||||
properties:
|
||||
env: hangzhou
|
||||
# 将给杭州区用的 RDS 共享给北京区
|
||||
- name: share-hangzhou-rds-to-beijing
|
||||
type: share-cloud-resource
|
||||
properties:
|
||||
env: hangzhou
|
||||
placements:
|
||||
- cluster: cluster-beijing
|
||||
# 部署 RDS 给香港区用
|
||||
- name: deploy-hongkong-rds
|
||||
type: deploy-cloud-resource
|
||||
properties:
|
||||
env: hongkong
|
||||
# 将给香港区用的 RDS 共享给香港区其他项目用
|
||||
- name: share-hongkong-rds-to-other-namespace
|
||||
type: share-cloud-resource
|
||||
properties:
|
||||
env: hongkong
|
||||
placements:
|
||||
- cluster: cluster-hongkong
|
||||
namespace: hk-project-2
|
||||
- cluster: cluster-hongkong
|
||||
namespace: hk-project-3
|
||||
```
|
||||
@@ -47,6 +47,7 @@ const AllComponentTypes = "*"
|
||||
type MarkdownReference struct {
|
||||
Filter func(types.Capability) bool
|
||||
AllInOne bool
|
||||
ForceExample bool
|
||||
CustomDocHeader string
|
||||
DiscoveryMapper discoverymapper.DiscoveryMapper
|
||||
ParseReference
|
||||
@@ -255,6 +256,9 @@ func (ref *MarkdownReference) GenerateMarkdownForCap(ctx context.Context, c type
|
||||
|
||||
if sampleContent != "" {
|
||||
sample = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, exampleTitle, sampleContent)
|
||||
} else if ref.ForceExample {
|
||||
fmt.Printf("You must provide example doc for the new added definition \"%s\", place the example doc in the /refereces/docgen/def-doc folders, for more details refer to https://kubevela.io/docs/contributor/cli-ref-doc#how-the-docs-generated", capName)
|
||||
os.Exit(1)
|
||||
}
|
||||
if c.Category == types.CUECategory && baseDoc != "" {
|
||||
base = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, baseTitle, baseDoc)
|
||||
|
||||
@@ -232,4 +232,35 @@ var _ = Describe("Test addon rest api", func() {
|
||||
}, 30*time.Second, 300*time.Millisecond).Should(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Test addon dependency addon in other registry", func() {
|
||||
It("Test Operation of enable addon from other registry", func() {
|
||||
req := apisv1.EnableAddonRequest{}
|
||||
res := post("/addons/mock-dep-addon/enable", req)
|
||||
defer res.Body.Close()
|
||||
var addon apisv1.AddonStatusResponse
|
||||
Expect(decodeResponseBody(res, &addon)).Should(Succeed())
|
||||
Expect(addon.Name).Should(BeEquivalentTo("mock-dep-addon"))
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
status := get("/addons/mock-dep-addon/status")
|
||||
var newaddonStatus apisv1.AddonStatusResponse
|
||||
g.Expect(decodeResponseBody(status, &newaddonStatus)).Should(Succeed())
|
||||
g.Expect(newaddonStatus.Name).Should(BeEquivalentTo("mock-dep-addon"))
|
||||
g.Expect(newaddonStatus.InstalledVersion).Should(BeEquivalentTo("v1.0.0"))
|
||||
g.Expect(newaddonStatus.Phase).Should(BeEquivalentTo(apisv1.AddonPhaseEnabled))
|
||||
}, 30*time.Second, 300*time.Millisecond).Should(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Test enable an addon with specified registry", func() {
|
||||
It("Test with a not exist registry", func() {
|
||||
req := apisv1.EnableAddonRequest{
|
||||
RegistryName: "not-exist",
|
||||
}
|
||||
res := post("/addons/test-addon/enable", req)
|
||||
defer res.Body.Close()
|
||||
Expect(res.StatusCode).Should(BeEquivalentTo(400))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user