mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Feat: generate docs for reference automatically (#4377)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Feat: refactor hardcode example to embd.FS Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: refactor doc gen for general types Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: update generate format Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: generate terraform reference docs Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Feat: add definition reference generate script Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: refine output format Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: remove dup annotation Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: update doc Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: add i18n support Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Feat: add translation Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Feat: add policy definition gen Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: add compatibility for lable Annotation change Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: add more tests Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Feat: allow mark example doc url on annotation Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Fix: align vela show with vela def doc-gen, add vela def show equals with vela show Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -51,3 +51,4 @@ git-page/
|
||||
|
||||
# e2e rollout runtime image build
|
||||
runtime/rollout/e2e/tmp
|
||||
vela.json
|
||||
|
||||
2
Makefile
2
Makefile
@@ -14,7 +14,7 @@ test: vet lint staticcheck unit-test-core test-cli-gen
|
||||
|
||||
test-cli-gen:
|
||||
mkdir -p ./bin/doc
|
||||
go run ./hack/docgen/gen.go ./bin/doc
|
||||
go run ./hack/docgen/cli/gen.go ./bin/doc
|
||||
unit-test-core:
|
||||
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... ./apis/... | grep -v apiserver | grep -v applicationconfiguration)
|
||||
go test $(shell go list ./references/... | grep -v apiserver)
|
||||
|
||||
@@ -165,6 +165,7 @@ type Capability struct {
|
||||
Center string `json:"center,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Example string `json:"example,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Category CapabilityCategory `json:"category,omitempty"`
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ var DefaultKubeVelaNS = "vela-system"
|
||||
const (
|
||||
// AnnoDefinitionDescription is the annotation which describe what is the capability used for in a WorkloadDefinition/TraitDefinition Object
|
||||
AnnoDefinitionDescription = "definition.oam.dev/description"
|
||||
// AnnoDefinitionExampleURL is the annotation which describe url of usage examples of the capability, it will be loaded in documentation generate.
|
||||
AnnoDefinitionExampleURL = "definition.oam.dev/example-url"
|
||||
// AnnoDefinitionAlias is the annotation for definition alias
|
||||
AnnoDefinitionAlias = "definition.oam.dev/alias"
|
||||
// AnnoDefinitionIcon is the annotation which describe the icon url
|
||||
|
||||
@@ -4,13 +4,13 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Image Registry
|
||||
alias.config.oam.dev: Image Registry
|
||||
definition.oam.dev/description: Config information to authenticate image registry
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
multi-cluster.config.oam.dev: "true"
|
||||
type.config.oam.dev: image-registry
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -4,13 +4,13 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Image Registry
|
||||
alias.config.oam.dev: Image Registry
|
||||
definition.oam.dev/description: Config information to authenticate image registry
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
multi-cluster.config.oam.dev: "true"
|
||||
type.config.oam.dev: image-registry
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
## General
|
||||
|
||||
- list all configuration types
|
||||
- list all configuration types. Note before vela v1.5, the key is "custom.definition.oam.dev/catalog.config.oam.dev"
|
||||
```shell
|
||||
$ vela components --label custom.definition.oam.dev/catalog.config.oam.dev=velacore-config
|
||||
$ vela components --label catalog.config.oam.dev=velacore-config
|
||||
NAME DEFINITION
|
||||
config-dex-connector autodetects.core.oam.dev
|
||||
config-helm-repository autodetects.core.oam.dev
|
||||
|
||||
@@ -93,7 +93,7 @@ var _ = Describe("Test Kubectl Plugin", func() {
|
||||
var tempApp v1beta1.Application
|
||||
_ = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: app.Name}, &tempApp)
|
||||
return tempApp.Status.LatestRevision != nil
|
||||
}, 20*time.Second).Should(BeTrue())
|
||||
}, 20*time.Second, time.Second).Should(BeTrue())
|
||||
|
||||
By("live-diff application")
|
||||
err := os.WriteFile("live-diff-app.yaml", []byte(newApplication), 0644)
|
||||
@@ -108,7 +108,7 @@ var _ = Describe("Test Kubectl Plugin", func() {
|
||||
var tempApp v1beta1.Application
|
||||
_ = k8sClient.Get(ctx, client.ObjectKey{Namespace: "default", Name: app.Name}, &tempApp)
|
||||
return tempApp.Status.LatestRevision != nil
|
||||
}, 20*time.Second).Should(BeTrue())
|
||||
}, 20*time.Second, time.Second).Should(BeTrue())
|
||||
|
||||
output, err := e2e.Exec("kubectl-vela live-diff -f live-diff-app.yaml -d definitions")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -134,7 +134,7 @@ var _ = Describe("Test Kubectl Plugin", func() {
|
||||
cdName := "test-webapp-chart"
|
||||
output, _ := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", cdName))
|
||||
return output
|
||||
}, 20*time.Second).Should(ContainSubstring("Properties"))
|
||||
}, 20*time.Second, time.Second).Should(ContainSubstring("Specification"))
|
||||
})
|
||||
It("Test show componentDefinition def with raw Kube mode", func() {
|
||||
cdName := "kube-worker"
|
||||
@@ -978,20 +978,20 @@ spec:
|
||||
}
|
||||
`
|
||||
|
||||
var showCdResult = `# Properties
|
||||
var showCdResult = `# Specification
|
||||
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
|
||||
| cmd | Commands to run in the container | []string | false | |
|
||||
| count | specify number of tasks to run in parallel | int | true | 1 |
|
||||
| cmd | Commands to run in the container. | []string | false | |
|
||||
| count | specify number of tasks to run in parallel. | int | true | 1 |
|
||||
| restart | Define the job restart policy, the value can only be Never or OnFailure. By default, it's Never. | string | true | Never |
|
||||
| image | Which image would you like to use for your service | string | true | |
|
||||
| image | Which image would you like to use for your service. | string | true | |
|
||||
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
|
||||
|
||||
|
||||
`
|
||||
|
||||
var showTdResult = `# Properties
|
||||
var showTdResult = `# Specification
|
||||
+---------+-------------+----------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+---------+-------------+----------+----------+---------+
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
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
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://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.
|
||||
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 main
|
||||
150
hack/docgen/def/collect-translation/collect.go
Normal file
150
hack/docgen/def/collect-translation/collect.go
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var i18nDoc = map[string]map[string]string{}
|
||||
|
||||
const cnComp = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/components/references.md"
|
||||
const enComp = "../kubevela.io/docs/end-user/components/references.md"
|
||||
|
||||
/*
|
||||
const enTrait = "../kubevela.io/docs/end-user/traits/references.md"
|
||||
const cnTrait = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/traits/references.md"
|
||||
const enPolicy = "../kubevela.io/docs/end-user/policies/references.md"
|
||||
const cnPolicy = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/policies/references.md"
|
||||
const cnWorkflow = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/workflow/built-in-workflow-defs.md"
|
||||
const enWorkflow = "../kubevela.io/docs/end-user/workflow/built-in-workflow-defs.md"
|
||||
*/
|
||||
|
||||
func main() {
|
||||
|
||||
pathCN := flag.String("path-cn", cnComp, "specify the path of chinese reference doc.")
|
||||
pathEN := flag.String("path-en", enComp, "specify the path of english reference doc.")
|
||||
path := flag.String("path", "", "path of existing i18n json data, if specified, it will read the file and keep the old data with append only.")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *path != "" {
|
||||
data, err := ioutil.ReadFile(*path)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(data, &i18nDoc)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paths := strings.Split(*pathEN, ";")
|
||||
var enbuff string
|
||||
for _, v := range paths {
|
||||
if strings.TrimSpace(v) == "" {
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadFile(v)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
enbuff += string(data) + "\n"
|
||||
}
|
||||
|
||||
cnpaths := strings.Split(*pathCN, ";")
|
||||
var cnbuff string
|
||||
for _, v := range cnpaths {
|
||||
if strings.TrimSpace(v) == "" {
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadFile(v)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
cnbuff += string(data) + "\n"
|
||||
}
|
||||
|
||||
var entable, cntable = map[string]string{}, map[string]string{}
|
||||
ens := strings.Split(enbuff, "\n")
|
||||
for _, v := range ens {
|
||||
values := strings.Split(v, "|")
|
||||
if len(values) < 4 {
|
||||
continue
|
||||
}
|
||||
var a, b = 0, 1
|
||||
if values[0] == "" {
|
||||
a, b = 1, 2
|
||||
}
|
||||
key := strings.TrimSpace(values[a])
|
||||
desc := strings.Trim(strings.TrimSpace(values[b]), ".")
|
||||
if strings.Contains(key, "----") {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(desc) == "" {
|
||||
continue
|
||||
}
|
||||
if len(entable[key]) > len(desc) {
|
||||
continue
|
||||
}
|
||||
entable[key] = desc
|
||||
}
|
||||
|
||||
cns := strings.Split(cnbuff, "\n")
|
||||
for _, v := range cns {
|
||||
values := strings.Split(v, "|")
|
||||
if len(values) < 5 {
|
||||
continue
|
||||
}
|
||||
var a, b = 0, 1
|
||||
if values[0] == "" {
|
||||
a, b = 1, 2
|
||||
}
|
||||
key := strings.TrimSpace(values[a])
|
||||
desc := strings.Trim(strings.TrimSpace(values[b]), ".")
|
||||
if strings.Contains(key, "----") {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(desc) == "" {
|
||||
continue
|
||||
}
|
||||
if len(cntable[key]) > len(desc) {
|
||||
continue
|
||||
}
|
||||
cntable[key] = desc
|
||||
}
|
||||
|
||||
for k, v := range entable {
|
||||
|
||||
trans := i18nDoc[v]
|
||||
if trans == nil {
|
||||
trans = map[string]string{}
|
||||
}
|
||||
trans["Chinese"] = cntable[k]
|
||||
// fmt.Println("Key=", k, " | ", v, " | ", cntable[k])
|
||||
i18nDoc[v] = trans
|
||||
}
|
||||
output, err := json.MarshalIndent(i18nDoc, "", "\t")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
}
|
||||
72
hack/docgen/def/gen.go
Normal file
72
hack/docgen/def/gen.go
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/hack/docgen/def/mods"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := common.InitBaseRestConfig()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
path := flag.String("path", "", "specify the path of output")
|
||||
location := flag.String("location", "", "path of output")
|
||||
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")
|
||||
flag.Parse()
|
||||
|
||||
if *i18nfile != "" {
|
||||
plugins.LoadI18nData(*i18nfile)
|
||||
}
|
||||
|
||||
if *tp == "" && (*defdir != "" || *path != "") {
|
||||
fmt.Println("you must specify a type with definition ref path specified ")
|
||||
os.Exit(1)
|
||||
}
|
||||
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":
|
||||
mods.ComponentDef(ctx, c, path, location, *defdir)
|
||||
case types.TypeTrait:
|
||||
mods.TraitDef(ctx, c, path, location, *defdir)
|
||||
case types.TypePolicy:
|
||||
mods.PolicyDef(ctx, c, path, location, *defdir)
|
||||
case types.TypeWorkflowStep:
|
||||
mods.WorkflowDef(ctx, c, path, location, *defdir)
|
||||
default:
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
120
hack/docgen/def/mods/component.go
Normal file
120
hack/docgen/def/mods/component.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
// ComponentDefRefPath is the target path for kubevela.io component ref docs
|
||||
ComponentDefRefPath = "../kubevela.io/docs/end-user/components/references.md"
|
||||
// ComponentDefRefPathZh is the target path for kubevela.io component ref docs in Chinese
|
||||
ComponentDefRefPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/components/references.md"
|
||||
|
||||
// ComponentDefDir store inner CUE definition
|
||||
ComponentDefDir = "./vela-templates/definitions/internal/component/"
|
||||
)
|
||||
|
||||
// CustomComponentHeaderEN .
|
||||
var CustomComponentHeaderEN = `---
|
||||
title: Built-in Component Type
|
||||
---
|
||||
|
||||
This documentation will walk through all the built-in component types sorted alphabetically.
|
||||
|
||||
` + fmt.Sprintf("> It was generated automatically by [scripts](../../contributor/cli-ref-doc), please don't update manually, last updated at %s.\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// CustomComponentHeaderZH .
|
||||
var CustomComponentHeaderZH = `---
|
||||
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
|
||||
}
|
||||
ref := &plugins.MarkdownReference{
|
||||
AllInOne: true,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypeComponentDefinition || capability.Category != types.CUECategory {
|
||||
return false
|
||||
}
|
||||
if capability.Labels != nil && (capability.Labels[types.LabelDefinitionHidden] == "true" || capability.Labels[types.LabelDefinitionDeprecated] == "true") {
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), capability.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
CustomDocHeader: CustomComponentHeaderEN,
|
||||
}
|
||||
ref.Remote = &plugins.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
|
||||
if *path != "" {
|
||||
ref.I18N = &plugins.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomComponentHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomComponentHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPathZh)
|
||||
}
|
||||
}
|
||||
119
hack/docgen/def/mods/policy.go
Normal file
119
hack/docgen/def/mods/policy.go
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
// PolicyDefRefPath is the target path for kubevela.io policy ref docs
|
||||
PolicyDefRefPath = "../kubevela.io/docs/end-user/policies/references.md"
|
||||
// PolicyDefRefPathZh is the target path for kubevela.io policy ref docs in Chinese
|
||||
PolicyDefRefPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/policies/references.md"
|
||||
|
||||
// PolicyDefDir store inner CUE definition
|
||||
PolicyDefDir = "./vela-templates/definitions/internal/policy/"
|
||||
)
|
||||
|
||||
// CustomPolicyHeaderEN .
|
||||
var CustomPolicyHeaderEN = `---
|
||||
title: Built-in Policy Type
|
||||
---
|
||||
|
||||
This documentation will walk through all the built-in policy types sorted alphabetically.
|
||||
|
||||
` + fmt.Sprintf("> It was generated automatically by [scripts](../../contributor/cli-ref-doc), please don't update manually, last updated at %s.\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// CustomPolicyHeaderZH .
|
||||
var CustomPolicyHeaderZH = `---
|
||||
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
|
||||
}
|
||||
ref := &plugins.MarkdownReference{
|
||||
AllInOne: true,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypePolicy || capability.Category != types.CUECategory {
|
||||
return false
|
||||
}
|
||||
if capability.Labels != nil && (capability.Labels[types.LabelDefinitionHidden] == "true" || capability.Labels[types.LabelDefinitionDeprecated] == "true") {
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), capability.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
CustomDocHeader: CustomPolicyHeaderEN,
|
||||
}
|
||||
ref.Remote = &plugins.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
if *path != "" {
|
||||
ref.I18N = &plugins.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomPolicyHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomPolicyHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPathZh)
|
||||
}
|
||||
}
|
||||
120
hack/docgen/def/mods/trait.go
Normal file
120
hack/docgen/def/mods/trait.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
// TraitDefRefPath is the target path for kubevela.io trait ref docs
|
||||
TraitDefRefPath = "../kubevela.io/docs/end-user/traits/references.md"
|
||||
// TraitDefRefPathZh is the target path for kubevela.io trait ref docs in Chinese
|
||||
TraitDefRefPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/traits/references.md"
|
||||
|
||||
// TraitDefDir store inner CUE definition
|
||||
TraitDefDir = "./vela-templates/definitions/internal/trait/"
|
||||
)
|
||||
|
||||
// CustomTraitHeaderEN .
|
||||
var CustomTraitHeaderEN = `---
|
||||
title: Built-in Trait Type
|
||||
---
|
||||
|
||||
This documentation will walk through all the built-in trait types sorted alphabetically.
|
||||
|
||||
` + fmt.Sprintf("> It was generated automatically by [scripts](../../contributor/cli-ref-doc), please don't update manually, last updated at %s.\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// CustomTraitHeaderZH .
|
||||
var CustomTraitHeaderZH = `---
|
||||
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
|
||||
}
|
||||
ref := &plugins.MarkdownReference{
|
||||
AllInOne: true,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
if capability.Type != types.TypeTrait || capability.Category != types.CUECategory {
|
||||
return false
|
||||
}
|
||||
if capability.Labels != nil && (capability.Labels[types.LabelDefinitionDeprecated] == "true") {
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), capability.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
CustomDocHeader: CustomTraitHeaderEN,
|
||||
}
|
||||
ref.Remote = &plugins.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
|
||||
if *path != "" {
|
||||
ref.I18N = &plugins.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPathZh)
|
||||
}
|
||||
}
|
||||
122
hack/docgen/def/mods/workflow.go
Normal file
122
hack/docgen/def/mods/workflow.go
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
// WorkflowDefRefPath is the target path for kubevela.io workflow ref docs
|
||||
WorkflowDefRefPath = "../kubevela.io/docs/end-user/workflow/built-in-workflow-defs.md"
|
||||
// WorkflowDefRefPathZh is the target path for kubevela.io workflow ref docs in Chinese
|
||||
WorkflowDefRefPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/workflow/built-in-workflow-defs.md"
|
||||
|
||||
// WorkflowDefDir store inner CUE definition
|
||||
WorkflowDefDir = "./vela-templates/definitions/internal/workflowstep/"
|
||||
)
|
||||
|
||||
// CustomWorkflowHeaderEN .
|
||||
var CustomWorkflowHeaderEN = `---
|
||||
title: Built-in WorkflowStep Type
|
||||
---
|
||||
|
||||
This documentation will walk through all the built-in workflow step types sorted alphabetically.
|
||||
|
||||
` + fmt.Sprintf("> It was generated automatically by [scripts](../../contributor/cli-ref-doc), please don't update manually, last updated at %s.\n\n", time.Now().Format(time.RFC3339))
|
||||
|
||||
// CustomWorkflowHeaderZH .
|
||||
var CustomWorkflowHeaderZH = `---
|
||||
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
|
||||
}
|
||||
ref := &plugins.MarkdownReference{
|
||||
AllInOne: true,
|
||||
Filter: func(capability types.Capability) bool {
|
||||
|
||||
if capability.Type != types.TypeWorkflowStep || capability.Category != types.CUECategory {
|
||||
return false
|
||||
}
|
||||
|
||||
if capability.Labels != nil && (capability.Labels[types.LabelDefinitionHidden] == "true" || capability.Labels[types.LabelDefinitionDeprecated] == "true") {
|
||||
return false
|
||||
}
|
||||
// only print capability which contained in cue def
|
||||
files, err := ioutil.ReadDir(defdir)
|
||||
if err != nil {
|
||||
fmt.Println("read dir err", defdir, err)
|
||||
return false
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), capability.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
CustomDocHeader: CustomWorkflowHeaderEN,
|
||||
}
|
||||
ref.Remote = &plugins.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
|
||||
if *path != "" {
|
||||
ref.I18N = &plugins.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomWorkflowHeaderZH
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &plugins.Zh
|
||||
ref.CustomDocHeader = CustomWorkflowHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPathZh)
|
||||
}
|
||||
}
|
||||
87
hack/docgen/terraform/generate.go
Normal file
87
hack/docgen/terraform/generate.go
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
// KubeVelaIOTerraformPath is the target path for kubevela.io terraform docs
|
||||
KubeVelaIOTerraformPath = "../kubevela.io/docs/end-user/components/cloud-services/terraform"
|
||||
// KubeVelaIOTerraformPathZh is the target path for kubevela.io terraform docs in Chinese
|
||||
KubeVelaIOTerraformPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/components/cloud-services/terraform"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ref := &plugins.MarkdownReference{}
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := common.InitBaseRestConfig()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
ref.Remote = &plugins.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
ref.Filter = func(capability types.Capability) bool {
|
||||
if capability.Labels != nil && capability.Labels[types.LabelDefinitionHidden] == "true" {
|
||||
return false
|
||||
}
|
||||
return capability.Type == types.TypeComponentDefinition && capability.Category == types.TerraformCategory
|
||||
}
|
||||
|
||||
path := flag.String("path", "", "path of output")
|
||||
location := flag.String("location", "", "path of output")
|
||||
i18nfile := flag.String("i18n", "../kubevela.io/static/reference-i18n.json", "file path of i18n data")
|
||||
flag.Parse()
|
||||
|
||||
if *i18nfile != "" {
|
||||
plugins.LoadI18nData(*i18nfile)
|
||||
}
|
||||
|
||||
if *path != "" {
|
||||
ref.I18N = &plugins.En
|
||||
if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") {
|
||||
ref.I18N = &plugins.Zh
|
||||
}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("terraform reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
ref.I18N = &plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, KubeVelaIOTerraformPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("terraform reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), KubeVelaIOTerraformPath)
|
||||
ref.I18N = &plugins.Zh
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, KubeVelaIOTerraformPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("terraform reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), KubeVelaIOTerraformPathZh)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
## Conflicts With
|
||||
|
||||
### `Autoscale`
|
||||
|
||||
When `Rollout` and `Autoscle` traits are attached to the same service, they two will fight over the number of instances during rollout. Thus, it's by design that `Rollout` will take over replicas control (specified by `.replicas` field) during rollout.
|
||||
|
||||
> Note: in up coming releases, KubeVela will introduce a separate section in Appfile to define release phase configurations such as `Rollout`.
|
||||
|
||||
## How `Rollout` works?
|
||||
|
||||
`Rollout` trait implements progressive release process to rollout your app following [Canary strategy](https://martinfowler.com/bliki/CanaryRelease.html).
|
||||
|
||||
In detail, `Rollout` controller will create a canary of your app , and then gradually shift traffic to the canary while measuring key performance indicators like HTTP requests success rate at the same time.
|
||||
|
||||
|
||||

|
||||
|
||||
In this sample, for every `10s`, `5%` traffic will be shifted to canary from the primary, until the traffic on canary reached `50%`. At the mean time, the instance number of canary will automatically scale to `replicas: 2` per configured in Appfile.
|
||||
|
||||
|
||||
Based on analysis result of the KPIs during this traffic shifting, a canary will be promoted or aborted if analysis is failed. If promoting, the primary will be upgraded from v1 to v2, and traffic will be fully shifted back to the primary instances. So as result, canary instances will be deleted after the promotion finished.
|
||||
|
||||

|
||||
|
||||
> Note: KubeVela's `Rollout` trait is implemented with [Weaveworks Flagger](https://flagger.app/) operator.
|
||||
@@ -1,50 +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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ref := &plugins.MarkdownReference{}
|
||||
ctx := context.Background()
|
||||
path := plugins.BaseRefPath
|
||||
|
||||
if len(os.Args) == 2 {
|
||||
ref.DefinitionName = os.Args[1]
|
||||
path = plugins.KubeVelaIOTerraformPath
|
||||
}
|
||||
|
||||
c, err := common.InitBaseRestConfig()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ref.Remote = &plugins.Remote{Namespace: types.DefaultKubeVelaNS}
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
)
|
||||
|
||||
@@ -286,7 +286,7 @@ func compareWorkflowSteps(old, new steps) steps {
|
||||
}
|
||||
}
|
||||
|
||||
_, needDeleted, needAdded := utils2.ThreeWaySliceCompare(oldTargets, newTargets)
|
||||
_, needDeleted, needAdded := pkgUtils.ThreeWaySliceCompare(oldTargets, newTargets)
|
||||
var workflowSteps []*workflowStep
|
||||
|
||||
var deployCloudResourcePolicyExist = false
|
||||
@@ -295,7 +295,7 @@ func compareWorkflowSteps(old, new steps) steps {
|
||||
var deletedPolicyCount = 0
|
||||
for i := range oldStep.policies {
|
||||
p := oldStep.policies[i]
|
||||
if utils2.SliceIncludeSlice(needDeleted, cacheTarget(oldStep.stepType, p.targets)) {
|
||||
if pkgUtils.SliceIncludeSlice(needDeleted, cacheTarget(oldStep.stepType, p.targets)) {
|
||||
p.state = deleteState
|
||||
deletedPolicyCount++
|
||||
}
|
||||
@@ -314,7 +314,7 @@ func compareWorkflowSteps(old, new steps) steps {
|
||||
newStep := new[j]
|
||||
for i := range newStep.policies {
|
||||
p := newStep.policies[i]
|
||||
if utils2.SliceIncludeSlice(needAdded, cacheTarget(newStep.stepType, p.targets)) {
|
||||
if pkgUtils.SliceIncludeSlice(needAdded, cacheTarget(newStep.stepType, p.targets)) {
|
||||
if p.policyType == v1alpha1.EnvBindingPolicyType && deployCloudResourcePolicyExist {
|
||||
p.state = updateState
|
||||
} else {
|
||||
@@ -418,7 +418,7 @@ func UpdateAppEnvWorkflow(ctx context.Context, kubeClient client.Client, ds data
|
||||
log.Logger.Errorf("fail to update the env workflow %s", envs[i].PrimaryKey())
|
||||
}
|
||||
}
|
||||
log.Logger.Infof("The env workflows of app %s updated successfully", utils2.Sanitize(app.PrimaryKey()))
|
||||
log.Logger.Infof("The env workflows of app %s updated successfully", pkgUtils.Sanitize(app.PrimaryKey()))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ func GenEnvWorkflowStepsAndPolicies(ctx context.Context, kubeClient client.Clien
|
||||
if step.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(step.Properties)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("workflow %s step %s properties is invalid %s", utils2.Sanitize(app.Name), utils2.Sanitize(step.Name), err.Error())
|
||||
log.Logger.Errorf("workflow %s step %s properties is invalid %s", pkgUtils.Sanitize(app.Name), pkgUtils.Sanitize(step.Name), err.Error())
|
||||
continue
|
||||
}
|
||||
s.Properties = properties
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
func TestCompareWorkflowSteps(t *testing.T) {
|
||||
@@ -543,7 +543,7 @@ func CreateEnvWorkflow(ctx context.Context, store datastore.DataStore, kubeClien
|
||||
EnvName: env.Name,
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
log.Logger.Infof("create workflow %s for app %s", utils2.Sanitize(workflow.Name), utils2.Sanitize(app.PrimaryKey()))
|
||||
log.Logger.Infof("create workflow %s for app %s", pkgUtils.Sanitize(workflow.Name), pkgUtils.Sanitize(app.PrimaryKey()))
|
||||
if err := store.Add(ctx, workflow); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/dryrun"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
commonutil "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
// PolicyType build-in policy type
|
||||
@@ -128,7 +128,7 @@ func listApp(ctx context.Context, ds datastore.DataStore, listOptions apisv1.Lis
|
||||
if listOptions.Env != "" || listOptions.TargetName != "" {
|
||||
envBinding, err = repository.ListFullEnvBinding(ctx, ds, repository.EnvListOption{})
|
||||
if err != nil {
|
||||
log.Logger.Errorf("list envbinding for list application in env %s err %v", utils2.Sanitize(listOptions.Env), err)
|
||||
log.Logger.Errorf("list envbinding for list application in env %s err %v", pkgUtils.Sanitize(listOptions.Env), err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ func (c *applicationServiceImpl) ListApplications(ctx context.Context, listOptio
|
||||
return []*apisv1.ApplicationBase{}, nil
|
||||
}
|
||||
if len(listOptions.Projects) > 0 {
|
||||
if !utils2.SliceIncludeSlice(availableProjectNames, listOptions.Projects) {
|
||||
if !pkgUtils.SliceIncludeSlice(availableProjectNames, listOptions.Projects) {
|
||||
return []*apisv1.ApplicationBase{}, nil
|
||||
}
|
||||
}
|
||||
@@ -595,7 +595,7 @@ func (c *applicationServiceImpl) DetailComponent(ctx context.Context, app *model
|
||||
}
|
||||
var cd v1beta1.ComponentDefinition
|
||||
if err := c.KubeClient.Get(ctx, types.NamespacedName{Name: component.Type, Namespace: velatypes.DefaultKubeVelaNS}, &cd); err != nil {
|
||||
log.Logger.Warnf("component definition %s get failure. %s", utils2.Sanitize(component.Type), err.Error())
|
||||
log.Logger.Warnf("component definition %s get failure. %s", pkgUtils.Sanitize(component.Type), err.Error())
|
||||
}
|
||||
|
||||
return &apisv1.DetailComponentResponse{
|
||||
@@ -1065,7 +1065,7 @@ func (c *applicationServiceImpl) UpdateComponent(ctx context.Context, app *model
|
||||
func (c *applicationServiceImpl) createComponent(ctx context.Context, app *model.Application, com apisv1.CreateComponentRequest, main bool) (*apisv1.ComponentBase, error) {
|
||||
var cd v1beta1.ComponentDefinition
|
||||
if err := c.KubeClient.Get(ctx, types.NamespacedName{Name: com.ComponentType, Namespace: velatypes.DefaultKubeVelaNS}, &cd); err != nil {
|
||||
log.Logger.Warnf("component definition %s get failure. %s", utils2.Sanitize(com.ComponentType), err.Error())
|
||||
log.Logger.Warnf("component definition %s get failure. %s", pkgUtils.Sanitize(com.ComponentType), err.Error())
|
||||
return nil, bcode.ErrComponentTypeNotSupport
|
||||
}
|
||||
userName, _ := ctx.Value(&apisv1.CtxKeyUser).(string)
|
||||
@@ -1120,7 +1120,7 @@ func (c *applicationServiceImpl) createComponent(ctx context.Context, app *model
|
||||
if errors.Is(err, datastore.ErrRecordExist) {
|
||||
return nil, bcode.ErrApplicationComponentExist
|
||||
}
|
||||
log.Logger.Warnf("add component for app %s failure %s", utils2.Sanitize(app.PrimaryKey()), err.Error())
|
||||
log.Logger.Warnf("add component for app %s failure %s", pkgUtils.Sanitize(app.PrimaryKey()), err.Error())
|
||||
return nil, err
|
||||
}
|
||||
// update the env workflow, the automatically generated workflow is determined by the component type.
|
||||
@@ -1491,8 +1491,8 @@ func (c *applicationServiceImpl) CompareApp(ctx context.Context, appModel *model
|
||||
return compareResponse, nil
|
||||
}
|
||||
|
||||
args := common2.Args{
|
||||
Schema: common2.Scheme,
|
||||
args := commonutil.Args{
|
||||
Schema: commonutil.Scheme,
|
||||
}
|
||||
_ = args.SetConfig(c.KubeConfig)
|
||||
args.SetClient(c.KubeClient)
|
||||
@@ -1534,8 +1534,8 @@ func (c *applicationServiceImpl) DryRunAppOrRevision(ctx context.Context, appMod
|
||||
default:
|
||||
return nil, bcode.ErrApplicationDryRunFailed.SetMessage("The dry run type is not supported")
|
||||
}
|
||||
args := common2.Args{
|
||||
Schema: common2.Scheme,
|
||||
args := commonutil.Args{
|
||||
Schema: commonutil.Scheme,
|
||||
}
|
||||
_ = args.SetConfig(c.KubeConfig)
|
||||
args.SetClient(c.KubeClient)
|
||||
@@ -1594,7 +1594,7 @@ func (c *applicationServiceImpl) resetApp(ctx context.Context, targetApp *v1beta
|
||||
targetCompNames = append(targetCompNames, comp.Name)
|
||||
}
|
||||
|
||||
readyToUpdate, readyToDelete, readyToAdd := utils2.ThreeWaySliceCompare(originCompNames, targetCompNames)
|
||||
readyToUpdate, readyToDelete, readyToAdd := pkgUtils.ThreeWaySliceCompare(originCompNames, targetCompNames)
|
||||
|
||||
// delete new app's components
|
||||
for _, compName := range readyToDelete {
|
||||
@@ -1626,11 +1626,11 @@ func (c *applicationServiceImpl) resetApp(ctx context.Context, targetApp *v1beta
|
||||
if errors.Is(err, datastore.ErrRecordExist) {
|
||||
err := c.Store.Put(ctx, &compModel)
|
||||
if err != nil {
|
||||
log.Logger.Warnf("update comp %s for app %s failure %s", comp.Name, utils2.Sanitize(appPrimaryKey), err.Error())
|
||||
log.Logger.Warnf("update comp %s for app %s failure %s", comp.Name, pkgUtils.Sanitize(appPrimaryKey), err.Error())
|
||||
}
|
||||
return &apisv1.AppResetResponse{IsReset: true}, err
|
||||
}
|
||||
log.Logger.Warnf("add comp %s for app %s failure %s", comp.Name, utils2.Sanitize(appPrimaryKey), err.Error())
|
||||
log.Logger.Warnf("add comp %s for app %s failure %s", comp.Name, pkgUtils.Sanitize(appPrimaryKey), err.Error())
|
||||
return &apisv1.AppResetResponse{}, err
|
||||
}
|
||||
}
|
||||
@@ -1638,7 +1638,7 @@ func (c *applicationServiceImpl) resetApp(ctx context.Context, targetApp *v1beta
|
||||
return &apisv1.AppResetResponse{IsReset: true}, nil
|
||||
}
|
||||
|
||||
func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Application) (bytes.Buffer, error) {
|
||||
func dryRunApplication(ctx context.Context, c commonutil.Args, app *v1beta1.Application) (bytes.Buffer, error) {
|
||||
var buff = bytes.Buffer{}
|
||||
if _, err := fmt.Fprintf(&buff, "---\n# Application(%s) \n---\n\n", app.Name); err != nil {
|
||||
return buff, fmt.Errorf("fail to write to buff %w", err)
|
||||
@@ -1696,7 +1696,7 @@ func ignoreSomeParams(o *v1beta1.Application) {
|
||||
*o = defaultApplication
|
||||
}
|
||||
|
||||
func compare(ctx context.Context, c common2.Args, targetApp *v1beta1.Application, baseApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
func compare(ctx context.Context, c commonutil.Args, targetApp *v1beta1.Application, baseApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
var buff = bytes.Buffer{}
|
||||
_, err := c.GetClient()
|
||||
if err != nil {
|
||||
|
||||
@@ -42,9 +42,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
definitionAlias = definition.UserPrefix + "alias.config.oam.dev"
|
||||
definitionType = definition.UserPrefix + "type.config.oam.dev"
|
||||
|
||||
configIsReady = "Ready"
|
||||
configIsNotReady = "Not ready"
|
||||
terraformProviderAlias = "Terraform Cloud Provider"
|
||||
@@ -74,20 +71,36 @@ type configServiceImpl struct {
|
||||
func (u *configServiceImpl) ListConfigTypes(ctx context.Context, query string) ([]*apis.ConfigType, error) {
|
||||
defs := &v1beta1.ComponentDefinitionList{}
|
||||
if err := u.KubeClient.List(ctx, defs, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig}); err != nil {
|
||||
client.MatchingLabels{
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var items []v1beta1.ComponentDefinition
|
||||
items = append(items, defs.Items...)
|
||||
|
||||
// for compatibility of the config catalog key
|
||||
defsLegacy := &v1beta1.ComponentDefinitionList{}
|
||||
if err := u.KubeClient.List(ctx, defsLegacy, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
// leave here as the legacy format to test the compatibility
|
||||
definition.UserPrefix + configCatalog: types.VelaCoreConfig,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, defsLegacy.Items...)
|
||||
|
||||
var tfDefs []v1beta1.ComponentDefinition
|
||||
var configTypes []*apis.ConfigType
|
||||
|
||||
for _, d := range defs.Items {
|
||||
if d.Labels[definitionType] == types.TerraformProvider {
|
||||
for _, d := range items {
|
||||
if DefinitionType(d.Labels) == types.TerraformProvider {
|
||||
tfDefs = append(tfDefs, d)
|
||||
continue
|
||||
}
|
||||
configTypes = append(configTypes, &apis.ConfigType{
|
||||
Alias: d.Annotations[definitionAlias],
|
||||
Alias: DefinitionAlias(d.Annotations),
|
||||
Name: d.Name,
|
||||
Definitions: []string{d.Name},
|
||||
Description: d.Annotations[types.AnnoDefinitionDescription],
|
||||
@@ -119,7 +132,7 @@ func (u *configServiceImpl) GetConfigType(ctx context.Context, configType string
|
||||
}
|
||||
|
||||
t := &apis.ConfigType{
|
||||
Alias: d.Annotations[definitionAlias],
|
||||
Alias: DefinitionAlias(d.Annotations),
|
||||
Name: configType,
|
||||
Description: d.Annotations[types.AnnoDefinitionDescription],
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestListConfigTypes(t *testing.T) {
|
||||
Name: "def1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
definitionType: types.TerraformProvider,
|
||||
},
|
||||
},
|
||||
@@ -74,7 +74,7 @@ func TestListConfigTypes(t *testing.T) {
|
||||
definitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func TestGetConfigType(t *testing.T) {
|
||||
definitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + "catalog.config.oam.dev": types.VelaCoreConfig,
|
||||
definition.UserPrefix + configCatalog: types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// EnvBindingService envbinding service
|
||||
@@ -129,7 +129,7 @@ func (e *envBindingServiceImpl) BatchCreateEnvBinding(ctx context.Context, app *
|
||||
continue
|
||||
}
|
||||
if err := e.Store.Add(ctx, envBindingModel); err != nil {
|
||||
log.Logger.Errorf("add envbinding %s failure %s", utils2.Sanitize(envBindingModel.Name), err.Error())
|
||||
log.Logger.Errorf("add envbinding %s failure %s", pkgUtils.Sanitize(envBindingModel.Name), err.Error())
|
||||
continue
|
||||
}
|
||||
err = e.createEnvWorkflow(ctx, app, env, i == 0)
|
||||
@@ -237,7 +237,7 @@ func (e *envBindingServiceImpl) createEnvWorkflow(ctx context.Context, app *mode
|
||||
EnvName: env.Name,
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
log.Logger.Infof("create workflow %s for app %s", utils2.Sanitize(workflow.Name), utils2.Sanitize(app.PrimaryKey()))
|
||||
log.Logger.Infof("create workflow %s for app %s", pkgUtils.Sanitize(workflow.Name), pkgUtils.Sanitize(app.PrimaryKey()))
|
||||
if err := e.Store.Add(ctx, workflow); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ func (p *projectServiceImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
if err != nil {
|
||||
klog.InfoS("failed to get component definition", "ComponentDefinition", configType, "err", err)
|
||||
} else {
|
||||
configs[i].ConfigTypeAlias = d.Annotations[definitionAlias]
|
||||
configs[i].ConfigTypeAlias = DefinitionAlias(d.Annotations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
pkg/apiserver/domain/service/tags.go
Normal file
61
pkg/apiserver/domain/service/tags.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 service
|
||||
|
||||
import "github.com/oam-dev/kubevela/pkg/definition"
|
||||
|
||||
const (
|
||||
definitionAlias = "alias.config.oam.dev"
|
||||
definitionType = "type.config.oam.dev"
|
||||
configCatalog = "catalog.config.oam.dev"
|
||||
)
|
||||
|
||||
// DefinitionAlias will get definitionAlias value from tags
|
||||
func DefinitionAlias(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[definitionAlias]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+definitionAlias]
|
||||
}
|
||||
|
||||
// DefinitionType will get definitionType value from tags
|
||||
func DefinitionType(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[definitionType]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+definitionType]
|
||||
}
|
||||
|
||||
// ConfigCatalog will get configCatalog value from tags
|
||||
func ConfigCatalog(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[configCatalog]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+configCatalog]
|
||||
}
|
||||
50
pkg/apiserver/domain/service/tags_test.go
Normal file
50
pkg/apiserver/domain/service/tags_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCompatiblleTag(t *testing.T) {
|
||||
tg := map[string]string{
|
||||
"alias.config.oam.dev": "abc",
|
||||
"type.config.oam.dev": "image-registry",
|
||||
"catalog.config.oam.dev": "cata",
|
||||
}
|
||||
|
||||
tgOld := map[string]string{
|
||||
"custom.definition.oam.dev/alias.config.oam.dev": "abc-2",
|
||||
"custom.definition.oam.dev/type.config.oam.dev": "image-registry-2",
|
||||
"custom.definition.oam.dev/catalog.config.oam.dev": "cata-2",
|
||||
}
|
||||
|
||||
assert.Equal(t, DefinitionAlias(nil), "")
|
||||
assert.Equal(t, DefinitionAlias(tg), "abc")
|
||||
assert.Equal(t, DefinitionAlias(tgOld), "abc-2")
|
||||
|
||||
assert.Equal(t, DefinitionType(nil), "")
|
||||
assert.Equal(t, DefinitionType(tg), "image-registry")
|
||||
assert.Equal(t, DefinitionType(tgOld), "image-registry-2")
|
||||
|
||||
assert.Equal(t, ConfigCatalog(nil), "")
|
||||
assert.Equal(t, ConfigCatalog(tg), "cata")
|
||||
assert.Equal(t, ConfigCatalog(tgOld), "cata-2")
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -151,7 +151,7 @@ func (u *userServiceImpl) DeleteUser(ctx context.Context, username string) error
|
||||
}
|
||||
}
|
||||
if err := u.Store.Delete(ctx, &model.User{Name: username}); err != nil {
|
||||
log.Logger.Errorf("failed to delete user %s %v", utils2.Sanitize(username), err.Error())
|
||||
log.Logger.Errorf("failed to delete user %s %v", pkgUtils.Sanitize(username), err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
)
|
||||
@@ -91,7 +91,7 @@ func (w *workflowServiceImpl) DeleteWorkflow(ctx context.Context, app *model.App
|
||||
}
|
||||
records, err := w.Store.List(ctx, &record, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
log.Logger.Errorf("list workflow %s record failure %s", utils2.Sanitize(workflow.PrimaryKey()), err.Error())
|
||||
log.Logger.Errorf("list workflow %s record failure %s", pkgUtils.Sanitize(workflow.PrimaryKey()), err.Error())
|
||||
}
|
||||
for _, record := range records {
|
||||
if err := w.Store.Delete(ctx, record); err != nil {
|
||||
@@ -186,7 +186,7 @@ func (w *workflowServiceImpl) CreateOrUpdateWorkflow(ctx context.Context, app *m
|
||||
EnvName: req.EnvName,
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
log.Logger.Infof("create workflow %s for app %s", utils2.Sanitize(req.Name), utils2.Sanitize(app.PrimaryKey()))
|
||||
log.Logger.Infof("create workflow %s for app %s", pkgUtils.Sanitize(req.Name), pkgUtils.Sanitize(app.PrimaryKey()))
|
||||
if err := w.Store.Add(ctx, workflow); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -284,7 +284,11 @@ func (def *Definition) FromCUE(val *cue.Value, templateString string) error {
|
||||
return err
|
||||
}
|
||||
for _k, _v := range _annotations {
|
||||
annotations[UserPrefix+_k] = _v
|
||||
if strings.Contains(_k, "oam.dev") {
|
||||
annotations[_k] = _v
|
||||
} else {
|
||||
annotations[UserPrefix+_k] = _v
|
||||
}
|
||||
}
|
||||
case "labels":
|
||||
var _labels map[string]string
|
||||
@@ -292,7 +296,11 @@ func (def *Definition) FromCUE(val *cue.Value, templateString string) error {
|
||||
return err
|
||||
}
|
||||
for _k, _v := range _labels {
|
||||
labels[UserPrefix+_k] = _v
|
||||
if strings.Contains(_k, "oam.dev") {
|
||||
labels[_k] = _v
|
||||
} else {
|
||||
labels[UserPrefix+_k] = _v
|
||||
}
|
||||
}
|
||||
case "attributes":
|
||||
if err := codec.Encode(_value, &spec); err != nil {
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/load"
|
||||
@@ -192,6 +193,7 @@ func TestHttpGetCaFile(t *testing.T) {
|
||||
err := testServer.ListenAndServeTLS("./testdata/server.crt", "./testdata/server.key")
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
time.Sleep(time.Millisecond)
|
||||
caFile, err := ioutil.ReadFile("./testdata/server.crt")
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
75
pkg/utils/load.go
Normal file
75
pkg/utils/load.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
j "encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
// ReadRemoteOrLocalPath will read a path remote or locally
|
||||
func ReadRemoteOrLocalPath(pathOrURL string, saveLocal bool) ([]byte, error) {
|
||||
var data []byte
|
||||
var err error
|
||||
switch {
|
||||
case pathOrURL == "-":
|
||||
data, err = ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case IsValidURL(pathOrURL):
|
||||
data, err = common.HTTPGetWithOption(context.Background(), pathOrURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
data, err = os.ReadFile(filepath.Clean(pathOrURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if saveLocal {
|
||||
if err = localSave(pathOrURL, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func localSave(url string, body []byte) error {
|
||||
var name string
|
||||
ext := filepath.Ext(url)
|
||||
switch ext {
|
||||
case ".json":
|
||||
name = "vela.json"
|
||||
case ".yaml", ".yml":
|
||||
name = "vela.yaml"
|
||||
default:
|
||||
if j.Valid(body) {
|
||||
name = "vela.json"
|
||||
} else {
|
||||
name = "vela.yaml"
|
||||
}
|
||||
}
|
||||
//nolint:gosec
|
||||
return os.WriteFile(name, body, 0644)
|
||||
}
|
||||
49
pkg/utils/load_test.go
Normal file
49
pkg/utils/load_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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 utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReadRemoteOrLocalPath(t *testing.T) {
|
||||
go func() {
|
||||
svr := http.NewServeMux()
|
||||
svr.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{"Outputs":{"Chinese":"输出"}}`)
|
||||
})
|
||||
http.ListenAndServe(":65503", svr)
|
||||
}()
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
_, err := ReadRemoteOrLocalPath("http://127.0.0.1:65503", false)
|
||||
assert.NoError(t, err)
|
||||
_, err = ReadRemoteOrLocalPath("http://127.0.0.1:65503", true)
|
||||
assert.NoError(t, err)
|
||||
_, err = ReadRemoteOrLocalPath("vela.json", false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = os.Remove("vela.json")
|
||||
assert.NoError(t, err)
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// QueryView contains query data
|
||||
@@ -98,7 +98,7 @@ func ParseVelaQL(ql string) (QueryView, error) {
|
||||
|
||||
// ParseVelaQLFromPath will parse a velaQL file path to QueryView
|
||||
func ParseVelaQLFromPath(velaQLViewPath string) (*QueryView, error) {
|
||||
body, err := common.ReadRemoteOrLocalPath(velaQLViewPath)
|
||||
body, err := utils.ReadRemoteOrLocalPath(velaQLViewPath, false)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("read view file from %s: %v", velaQLViewPath, err)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks/template"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
refcommon "github.com/oam-dev/kubevela/references/common"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -197,7 +196,7 @@ func ParseViewIntoConfigMap(viewStr, name string) (*v1.ConfigMap, error) {
|
||||
//
|
||||
// By saying file, it can actually be a file, URL, or stdin (-).
|
||||
func StoreViewFromFile(ctx context.Context, c client.Client, path, viewName string) error {
|
||||
content, err := refcommon.ReadRemoteOrLocalPath(path)
|
||||
content, err := utils.ReadRemoteOrLocalPath(path, false)
|
||||
if err != nil {
|
||||
return errors.Errorf("cannot load cue file: %v", err)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// Run will deploy OAM objects and other assistant K8s Objects including ConfigMap, OAM Scope Custom Resource.
|
||||
@@ -85,3 +87,12 @@ func CreateOrUpdateApplication(ctx context.Context, client client.Client, app *v
|
||||
app.ResourceVersion = geta.ResourceVersion
|
||||
return client.Update(ctx, app)
|
||||
}
|
||||
|
||||
// BuildRun will build application and deploy from Appfile
|
||||
func BuildRun(ctx context.Context, app *api.Application, client client.Client, namespace string, io util.IOStreams) error {
|
||||
o, err := app.ConvertToApplication(namespace, io, app.Tm, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Run(ctx, client, o, nil)
|
||||
}
|
||||
|
||||
@@ -205,7 +205,6 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
|
||||
// AdditionalEndpointPrinter will print endpoints
|
||||
func AdditionalEndpointPrinter(ctx context.Context, c common.Args, k8sClient client.Client, name string, isUpgrade bool) {
|
||||
fmt.Printf("Please access %s from the following endpoints:\n", name)
|
||||
err := printAppEndpoints(ctx, addonutil.Addon2AppName(name), types.DefaultKubeVelaNS, Filter{}, c, true)
|
||||
if err != nil {
|
||||
fmt.Println("Get application endpoints error:", err)
|
||||
|
||||
@@ -107,7 +107,7 @@ func NewCommandWithIOStreams(ioStream util.IOStreams) *cobra.Command {
|
||||
// Extension
|
||||
NewAddonCommand(commandArgs, "9", ioStream),
|
||||
NewUISchemaCommand(commandArgs, "8", ioStream),
|
||||
DefinitionCommandGroup(commandArgs, "7"),
|
||||
DefinitionCommandGroup(commandArgs, "7", ioStream),
|
||||
NewRegistryCommand(ioStream, "6"),
|
||||
NewTraitCommand(commandArgs, ioStream),
|
||||
NewComponentsCommand(commandArgs, ioStream),
|
||||
|
||||
@@ -56,8 +56,7 @@ import (
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/filters"
|
||||
clicom "github.com/oam-dev/kubevela/references/common"
|
||||
"github.com/oam-dev/kubevela/references/plugins"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -68,7 +67,7 @@ const (
|
||||
)
|
||||
|
||||
// DefinitionCommandGroup create the command group for `vela def` command to manage definitions
|
||||
func DefinitionCommandGroup(c common.Args, order string) *cobra.Command {
|
||||
func DefinitionCommandGroup(c common.Args, order string, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "def",
|
||||
Short: "Manage Definitions",
|
||||
@@ -87,7 +86,8 @@ func DefinitionCommandGroup(c common.Args, order string) *cobra.Command {
|
||||
NewDefinitionDelCommand(c),
|
||||
NewDefinitionInitCommand(c),
|
||||
NewDefinitionValidateCommand(c),
|
||||
NewDefinitionGenDocCommand(c),
|
||||
NewDefinitionGenDocCommand(c, ioStreams),
|
||||
NewCapabilityShowCommand(c, ioStreams),
|
||||
NewDefinitionGenAPICommand(c),
|
||||
)
|
||||
return cmd
|
||||
@@ -115,7 +115,7 @@ func getPrompt(cmd *cobra.Command, reader *bufio.Reader, description string, pro
|
||||
}
|
||||
|
||||
func buildTemplateFromYAML(templateYAML string, def *pkgdef.Definition) error {
|
||||
templateYAMLBytes, err := clicom.ReadRemoteOrLocalPath(templateYAML)
|
||||
templateYAMLBytes, err := utils.ReadRemoteOrLocalPath(templateYAML, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get template YAML file %s", templateYAML)
|
||||
}
|
||||
@@ -511,65 +511,42 @@ func NewDefinitionGetCommand(c common.Args) *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to get. If empty, all types will be searched. Valid types: "+strings.Join(pkgdef.ValidDefinitionTypes(), ", "))
|
||||
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
|
||||
cmd.Flags().BoolVarP(&listRevisions, "revisions", "", false, "List revisions of the specified definition.")
|
||||
cmd.Flags().StringVarP(&targetRevision, "revision", "r", "", "Get the specified version of a definition.")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewDefinitionGenDocCommand create the `vela def doc-gen` command to generate documentation of definitions
|
||||
func NewDefinitionGenDocCommand(c common.Args) *cobra.Command {
|
||||
func NewDefinitionGenDocCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var path, location, i18nPath string
|
||||
cmd := &cobra.Command{
|
||||
Use: "doc-gen NAME",
|
||||
Short: "Generate documentation of definitions (Only Terraform typed definitions are supported)",
|
||||
Long: "Generate documentation of definitions",
|
||||
Example: "1. Generate documentation for ComponentDefinition alibaba-vpc:\n" +
|
||||
"> vela def doc-gen alibaba-vpc -n vela-system\n" +
|
||||
"2. Generate documentation for local ComponentDefinition file alibaba-vpc.yaml:\n" +
|
||||
Short: "Generate documentation for definitions",
|
||||
Long: "Generate documentation for definitions",
|
||||
Example: "1. Generate documentation for ComponentDefinition webservice:\n" +
|
||||
"> vela def doc-gen webservice -n vela-system\n" +
|
||||
"2. Generate documentation for local CUE Definition file webservice.cue:\n" +
|
||||
"> vela def doc-gen webservice.cue\n" +
|
||||
"3. Generate documentation for local Cloud Resource Definition YAML alibaba-vpc.yaml:\n" +
|
||||
"> vela def doc-gen alibaba-vpc.yaml\n",
|
||||
Deprecated: "This command has been replaced by 'vela show' or 'vela def show'.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("please specify definition name or a definition file")
|
||||
return fmt.Errorf("please specify definition name, cue file or a cloud resource definition yaml")
|
||||
}
|
||||
|
||||
ref := &plugins.MarkdownReference{}
|
||||
if strings.HasSuffix(args[0], ".yaml") {
|
||||
// read from local file
|
||||
localFilePath := args[0]
|
||||
fileName := filepath.Base(localFilePath)
|
||||
if !strings.HasSuffix(fileName, ".yaml") {
|
||||
return fmt.Errorf("invalid local file path `%s`", localFilePath)
|
||||
}
|
||||
ref.DefinitionName = strings.TrimSuffix(fileName, ".yaml")
|
||||
ref.Local = &plugins.Local{Path: localFilePath}
|
||||
} else {
|
||||
namespace, err := cmd.Flags().GetString(FlagNamespace)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get `%s`", Namespace)
|
||||
}
|
||||
ref.DefinitionName = args[0]
|
||||
ref.Remote = &plugins.Remote{Namespace: namespace}
|
||||
namespace, err := cmd.Flags().GetString(FlagNamespace)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get `%s`", Namespace)
|
||||
}
|
||||
return ShowReferenceMarkdown(context.Background(), c, ioStreams, args[0], path, location, i18nPath, namespace, 0)
|
||||
|
||||
ctx := context.Background()
|
||||
pathEn := plugins.KubeVelaIOTerraformPath
|
||||
ref.I18N = plugins.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, pathEn); err != nil {
|
||||
return errors.Wrap(err, "failed to generate reference docs")
|
||||
}
|
||||
cmd.Printf("Generated docs in English for %s in %s/%s.md\n", args[0], pathEn, ref.DefinitionName)
|
||||
|
||||
pathZh := plugins.KubeVelaIOTerraformPathZh
|
||||
ref.I18N = plugins.Zh
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, pathZh); err != nil {
|
||||
return errors.Wrap(err, "failed to generate reference docs")
|
||||
}
|
||||
cmd.Printf("Generated docs in Chinese for %s in %s/%s.md\n", args[0], pathZh, ref.DefinitionName)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP(Namespace, "n", "", "Specify the namespace of the definition.")
|
||||
cmd.Flags().StringVarP(&path, "path", "p", "", "Specify the path for of the doc generated from definition.")
|
||||
cmd.Flags().StringVarP(&location, "location", "l", "", "specify the location for of the doc generated from definition, now supported options 'zh', 'en'. ")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
cmd.Flags().StringVarP(&i18nPath, "i18n", "", "https://kubevela.io/reference-i18n.json", "specify the location for of the doc generated from definition, now supported options 'zh', 'en'. ")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -654,8 +631,8 @@ func NewDefinitionListCommand(c common.Args) *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to list. If empty, all types will be searched. Valid types: "+strings.Join(pkgdef.ValidDefinitionTypes(), ", "))
|
||||
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to list. If empty, all namespaces will be searched.")
|
||||
cmd.Flags().String("from", "", "Filter definitions by which addon installed them.")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -743,7 +720,7 @@ func NewDefinitionEditCommand(c common.Args) *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to get. If empty, all types will be searched. Valid types: "+strings.Join(pkgdef.ValidDefinitionTypes(), ", "))
|
||||
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -782,7 +759,7 @@ func NewDefinitionRenderCommand(c common.Args) *cobra.Command {
|
||||
}
|
||||
|
||||
render := func(inputFilename, outputFilename string) error {
|
||||
cueBytes, err := clicom.ReadRemoteOrLocalPath(inputFilename)
|
||||
cueBytes, err := utils.ReadRemoteOrLocalPath(inputFilename, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get %s", args[0])
|
||||
}
|
||||
@@ -901,7 +878,7 @@ func NewDefinitionApplyCommand(c common.Args) *cobra.Command {
|
||||
return errors.Wrapf(err, "failed to get k8s client")
|
||||
}
|
||||
defpath := args[0]
|
||||
defBytes, err := clicom.ReadRemoteOrLocalPath(defpath)
|
||||
defBytes, err := utils.ReadRemoteOrLocalPath(defpath, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get from %s", defpath)
|
||||
}
|
||||
@@ -967,7 +944,7 @@ func NewDefinitionApplyCommand(c common.Args) *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolP(FlagDryRun, "", false, "only build definition from CUE into CRB object without applying it to kubernetes clusters")
|
||||
cmd.Flags().StringP(Namespace, "n", "vela-system", "Specify which namespace to apply.")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -1032,7 +1009,7 @@ func NewDefinitionDelCommand(c common.Args) *cobra.Command {
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP(FlagType, "t", "", "Specify the definition type of target. Valid types: "+strings.Join(pkgdef.ValidDefinitionTypes(), ", "))
|
||||
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace the definition locates.")
|
||||
cmd.Flags().StringP(Namespace, "n", types.DefaultKubeVelaNS, "Specify which namespace the definition locates.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
pkgdef "github.com/oam-dev/kubevela/pkg/definition"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -179,7 +180,7 @@ func removeDir(dirname string, t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewDefinitionCommandGroup(t *testing.T) {
|
||||
cmd := DefinitionCommandGroup(common2.Args{}, "")
|
||||
cmd := DefinitionCommandGroup(common2.Args{}, "", cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
|
||||
initCommand(cmd)
|
||||
cmd.SetArgs([]string{"-h"})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
@@ -396,7 +397,7 @@ func TestNewDefinitionGetCommand(t *testing.T) {
|
||||
cmd := NewDefinitionGetCommand(c)
|
||||
initCommand(cmd)
|
||||
traitName := createTrait(c, t)
|
||||
cmd.SetArgs([]string{traitName})
|
||||
cmd.SetArgs([]string{traitName, "-n" + VelaTestNamespace})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("unexpeced error when executing get command: %v", err)
|
||||
}
|
||||
@@ -459,7 +460,7 @@ func TestNewDefinitionGetCommand(t *testing.T) {
|
||||
|
||||
func TestNewDefinitionGenDocCommand(t *testing.T) {
|
||||
c := initArgs()
|
||||
cmd := NewDefinitionGenDocCommand(c)
|
||||
cmd := NewDefinitionGenDocCommand(c, cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
|
||||
assert.NotNil(t, cmd.Execute())
|
||||
|
||||
cmd.SetArgs([]string{"alibaba-xxxxxxx"})
|
||||
@@ -501,7 +502,7 @@ func TestNewDefinitionEditCommand(t *testing.T) {
|
||||
if err := os.Setenv("EDITOR", "sed -i -e 's/test-trait/TestTrait/g'"); err != nil {
|
||||
t.Fatalf("failed to set editor env: %v", err)
|
||||
}
|
||||
cmd.SetArgs([]string{traitName})
|
||||
cmd.SetArgs([]string{traitName, "-n", VelaTestNamespace})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("unexpeced error when executing edit command: %v", err)
|
||||
}
|
||||
@@ -585,7 +586,7 @@ func TestNewDefinitionDelCommand(t *testing.T) {
|
||||
traitName := createTrait(c, t)
|
||||
reader := strings.NewReader("yes\n")
|
||||
cmd.SetIn(reader)
|
||||
cmd.SetArgs([]string{traitName})
|
||||
cmd.SetArgs([]string{traitName, "-n", VelaTestNamespace})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("unexpeced error when executing del command: %v", err)
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
clicom "github.com/oam-dev/kubevela/references/common"
|
||||
)
|
||||
|
||||
// DryRunCmdOptions contains dry-run cmd options
|
||||
@@ -200,7 +200,7 @@ func ReadObjectsFromFile(path string) ([]oam.Object, error) {
|
||||
}
|
||||
|
||||
func readApplicationFromFile(filename string) (*corev1beta1.Application, error) {
|
||||
fileContent, err := clicom.ReadRemoteOrLocalPath(filename)
|
||||
fileContent, err := utils.ReadRemoteOrLocalPath(filename, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func NewInitCommand(c common2.Args, order string, ioStreams cmdutil.IOStreams) *
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err = common.BuildRun(ctx, o.app, o.client, o.Namespace, o.IOStreams)
|
||||
err = appfile.BuildRun(ctx, o.app, o.client, o.Namespace, o.IOStreams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -36,10 +36,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -743,33 +741,5 @@ func ParseCapability(mapper discoverymapper.DiscoveryMapper, data []byte) (types
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
switch obj.GetKind() {
|
||||
case "ComponentDefinition":
|
||||
var cd v1beta1.ComponentDefinition
|
||||
err = yaml.Unmarshal(data, &cd)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
var workloadDefinitionRef string
|
||||
if cd.Spec.Workload.Type != "" {
|
||||
workloadDefinitionRef = cd.Spec.Workload.Type
|
||||
} else {
|
||||
ref, err := util.ConvertWorkloadGVK2Definition(mapper, cd.Spec.Workload.Definition)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
workloadDefinitionRef = ref.Name
|
||||
}
|
||||
return plugins.HandleDefinition(cd.Name, workloadDefinitionRef, cd.Annotations, cd.Labels, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic, nil)
|
||||
case "TraitDefinition":
|
||||
var td v1beta1.TraitDefinition
|
||||
err = yaml.Unmarshal(data, &td)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return plugins.HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Labels, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic, nil)
|
||||
case "ScopeDefinition":
|
||||
// TODO(wonderflow): support scope definition here.
|
||||
}
|
||||
return types.Capability{}, fmt.Errorf("unknown definition Type %s", obj.GetKind())
|
||||
return plugins.ParseCapabilityFromUnstructured(mapper, obj)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -31,6 +30,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
@@ -60,51 +60,71 @@ const (
|
||||
)
|
||||
|
||||
var webSite bool
|
||||
var showFormat string
|
||||
|
||||
// NewCapabilityShowCommand shows the reference doc for a component type or trait
|
||||
func NewCapabilityShowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
var revision string
|
||||
var revision, path, location, i18nPath string
|
||||
cmd := &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show the reference doc for a component, trait or workflow.",
|
||||
Long: "Show the reference doc for component, trait or workflow types.",
|
||||
Example: `show webservice`,
|
||||
Use: "show",
|
||||
Short: "Show the reference doc for a component, trait, policy or workflow.",
|
||||
Long: "Show the reference doc for component, trait, policy or workflow types. 'vela show' equals with 'vela def show'. ",
|
||||
Example: `0. Run 'vela show' directly to start a web server for all reference docs.
|
||||
1. Generate documentation for ComponentDefinition webservice:
|
||||
> vela show webservice -n vela-system
|
||||
2. Generate documentation for local CUE Definition file webservice.cue:
|
||||
> vela show webservice.cue
|
||||
3. Generate documentation for local Cloud Resource Definition YAML alibaba-vpc.yaml:
|
||||
> vela show alibaba-vpc.yaml
|
||||
4. Specify output format, markdown supported:
|
||||
> vela show webservice --format markdown
|
||||
5. Specify a language for output, by default, it's english. You can also load your own translation script:
|
||||
> vela show webservice --location zh
|
||||
> vela show webservice --location zh --i18n https://kubevela.io/reference-i18n.json
|
||||
6. Show doc for a specified revision, it must exist in control plane cluster:
|
||||
> vela show webservice --revision v1
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("please specify a component type or trait")
|
||||
}
|
||||
ctx := context.Background()
|
||||
capabilityName := args[0]
|
||||
var capabilityName string
|
||||
if len(args) > 0 {
|
||||
capabilityName = args[0]
|
||||
} else {
|
||||
cmd.Println("opening a browser for all capability docs...")
|
||||
webSite = true
|
||||
}
|
||||
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if revision == "" {
|
||||
if webSite {
|
||||
return startReferenceDocsSite(ctx, namespace, c, ioStreams, capabilityName)
|
||||
var ver int
|
||||
if revision != "" {
|
||||
// v1, 1, both need to work
|
||||
version := strings.TrimPrefix(revision, "v")
|
||||
ver, err = strconv.Atoi(version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid revision: %w", err)
|
||||
}
|
||||
return ShowReferenceConsole(ctx, c, ioStreams, capabilityName, namespace, 0)
|
||||
}
|
||||
|
||||
// v1, 1, both need to work
|
||||
version := strings.TrimPrefix(revision, "v")
|
||||
ver, err := strconv.Atoi(version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid revision: %w", err)
|
||||
}
|
||||
if webSite {
|
||||
return startReferenceDocsSite(ctx, namespace, c, ioStreams, capabilityName)
|
||||
}
|
||||
return ShowReferenceConsole(ctx, c, ioStreams, capabilityName, namespace, int64(ver))
|
||||
if path != "" || showFormat == "md" || showFormat == "markdown" {
|
||||
return ShowReferenceMarkdown(ctx, c, ioStreams, capabilityName, path, location, i18nPath, namespace, int64(ver))
|
||||
}
|
||||
return ShowReferenceConsole(ctx, c, ioStreams, capabilityName, namespace, location, i18nPath, int64(ver))
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeStart,
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&webSite, "web", "", false, " start web doc site")
|
||||
cmd.Flags().BoolVarP(&webSite, "web", "", false, "start web doc site")
|
||||
cmd.Flags().StringVarP(&showFormat, "format", "", "", "specify format of output data, by default it's a pretty human readable format, you can specify markdown(md)")
|
||||
cmd.Flags().StringVarP(&revision, "revision", "r", "", "Get the specified revision of a definition. Use def get to list revisions.")
|
||||
cmd.Flags().StringVarP(&path, "path", "p", "", "Specify the path for of the doc generated from definition.")
|
||||
cmd.Flags().StringVarP(&location, "location", "l", "", "specify the location for of the doc generated from definition, now supported options 'zh', 'en'. ")
|
||||
cmd.Flags().StringVarP(&i18nPath, "i18n", "", "https://kubevela.io/reference-i18n.json", "specify the location for of the doc generated from definition, now supported options 'zh', 'en'. ")
|
||||
|
||||
addNamespaceAndEnvArg(cmd)
|
||||
cmd.SetOut(ioStreams.Out)
|
||||
@@ -132,6 +152,10 @@ func startReferenceDocsSite(ctx context.Context, ns string, c common.Args, ioStr
|
||||
var capabilityIsValid bool
|
||||
var capabilityType types.CapType
|
||||
for _, c := range capabilities {
|
||||
if capabilityName == "" {
|
||||
capabilityIsValid = true
|
||||
break
|
||||
}
|
||||
if c.Name == capabilityName {
|
||||
capabilityIsValid = true
|
||||
capabilityType = c.Type
|
||||
@@ -139,7 +163,7 @@ func startReferenceDocsSite(ctx context.Context, ns string, c common.Args, ioStr
|
||||
}
|
||||
}
|
||||
if !capabilityIsValid {
|
||||
return fmt.Errorf("%s is not a valid component, trait or workflow", capabilityName)
|
||||
return fmt.Errorf("%s is not a valid component, trait, policy or workflow", capabilityName)
|
||||
}
|
||||
|
||||
cli, err := c.GetClient()
|
||||
@@ -149,6 +173,7 @@ func startReferenceDocsSite(ctx context.Context, ns string, c common.Args, ioStr
|
||||
ref := &plugins.MarkdownReference{
|
||||
ParseReference: plugins.ParseReference{
|
||||
Client: cli,
|
||||
I18N: &plugins.En,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -160,7 +185,7 @@ func startReferenceDocsSite(ctx context.Context, ns string, c common.Args, ioStr
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ref.CreateMarkdown(ctx, capabilities, docsPath, plugins.ReferenceSourcePath, pd); err != nil {
|
||||
if err := ref.CreateMarkdown(ctx, capabilities, docsPath, true, pd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -184,11 +209,14 @@ func startReferenceDocsSite(ctx context.Context, ns string, c common.Args, ioStr
|
||||
}
|
||||
|
||||
if capabilityType != types.TypeWorkload && capabilityType != types.TypeTrait && capabilityType != types.TypeScope &&
|
||||
capabilityType != types.TypeComponentDefinition && capabilityType != types.TypeWorkflowStep {
|
||||
capabilityType != types.TypeComponentDefinition && capabilityType != types.TypeWorkflowStep && capabilityType != "" {
|
||||
return fmt.Errorf("unsupported type: %v", capabilityType)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://127.0.0.1%s/#/%s/%s", Port, capabilityType, capabilityName)
|
||||
var suffix = capabilityName
|
||||
if suffix != "" {
|
||||
suffix = "/" + suffix
|
||||
}
|
||||
url := fmt.Sprintf("http://127.0.0.1%s/#/%s%s", Port, capabilityType, suffix)
|
||||
server := &http.Server{
|
||||
Addr: Port,
|
||||
Handler: http.FileServer(http.Dir(docsPath)),
|
||||
@@ -298,7 +326,7 @@ func generateIndexHTML(docsPath string) error {
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'KubeVela Reference Docs',
|
||||
name: 'KubeVela Customized Reference Docs',
|
||||
loadSidebar: true,
|
||||
loadNavbar: true,
|
||||
subMaxLevel: 1,
|
||||
@@ -402,73 +430,64 @@ func getDefinitions(capabilities []types.Capability) ([]string, []string, []stri
|
||||
}
|
||||
|
||||
// ShowReferenceConsole will show capability reference in console
|
||||
func ShowReferenceConsole(ctx context.Context, c common.Args, ioStreams cmdutil.IOStreams, capabilityName string, ns string, rev int64) error {
|
||||
config, err := c.GetConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pd, err := packages.NewPackageDiscover(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var capability *types.Capability
|
||||
|
||||
if rev == 0 {
|
||||
capability, err = plugins.GetCapabilityByName(ctx, c, capabilityName, ns, pd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
capability, err = plugins.GetCapabilityFromDefinitionRevision(ctx, c, pd, ns, capabilityName, rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func ShowReferenceConsole(ctx context.Context, c common.Args, ioStreams cmdutil.IOStreams, capabilityName string, ns, location, i18nPath string, rev int64) error {
|
||||
cli, err := c.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ref := &plugins.ConsoleReference{
|
||||
ParseReference: plugins.ParseReference{
|
||||
Client: cli,
|
||||
},
|
||||
ref := &plugins.ConsoleReference{}
|
||||
paserRef, err := genRefParser(capabilityName, ns, location, i18nPath, rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
paserRef.Client = cli
|
||||
ref.ParseReference = paserRef
|
||||
return ref.Show(ctx, c, ioStreams, capabilityName, ns, rev)
|
||||
}
|
||||
|
||||
var propertyConsole []plugins.ConsoleReference
|
||||
switch capability.Category {
|
||||
case types.HelmCategory:
|
||||
_, propertyConsole, err = ref.GenerateHelmAndKubeProperties(ctx, capability)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.KubeCategory:
|
||||
_, propertyConsole, err = ref.GenerateHelmAndKubeProperties(ctx, capability)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.CUECategory:
|
||||
propertyConsole, err = ref.GenerateCUETemplateProperties(capability, pd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.TerraformCategory:
|
||||
propertyConsole, err = ref.GenerateTerraformCapabilityProperties(*capability)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupport capability category %s", capability.Category)
|
||||
// ShowReferenceMarkdown will show capability in "markdown" format
|
||||
func ShowReferenceMarkdown(ctx context.Context, c common.Args, ioStreams cmdutil.IOStreams, capabilityNameOrPath, outputPath, location, i18nPath, ns string, rev int64) error {
|
||||
ref := &plugins.MarkdownReference{}
|
||||
paserRef, err := genRefParser(capabilityNameOrPath, ns, location, i18nPath, rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range propertyConsole {
|
||||
ioStreams.Info(p.TableName)
|
||||
p.TableObject.Render()
|
||||
ioStreams.Info("\n")
|
||||
ref.ParseReference = paserRef
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, outputPath); err != nil {
|
||||
return errors.Wrap(err, "failed to generate reference docs")
|
||||
}
|
||||
if outputPath != "" {
|
||||
ioStreams.Infof("Generated docs in %s for %s in %s/%s.md\n", ref.I18N, capabilityNameOrPath, outputPath, ref.DefinitionName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genRefParser(capabilityNameOrPath, ns, location, i18nPath string, rev int64) (plugins.ParseReference, error) {
|
||||
ref := plugins.ParseReference{}
|
||||
if location != "" {
|
||||
plugins.LoadI18nData(i18nPath)
|
||||
}
|
||||
if strings.HasSuffix(capabilityNameOrPath, ".yaml") || strings.HasSuffix(capabilityNameOrPath, ".cue") {
|
||||
// read from local file
|
||||
localFilePath := capabilityNameOrPath
|
||||
fileName := filepath.Base(localFilePath)
|
||||
ref.DefinitionName = strings.TrimSuffix(strings.TrimSuffix(fileName, ".yaml"), ".cue")
|
||||
ref.Local = &plugins.FromLocal{Path: localFilePath}
|
||||
} else {
|
||||
ref.DefinitionName = capabilityNameOrPath
|
||||
ref.Remote = &plugins.FromCluster{Namespace: ns, Rev: rev}
|
||||
}
|
||||
switch strings.ToLower(location) {
|
||||
case "zh", "cn", "chinese":
|
||||
ref.I18N = &plugins.Zh
|
||||
case "", "en", "english":
|
||||
ref.I18N = &plugins.En
|
||||
default:
|
||||
return ref, fmt.Errorf("unknown location %s for i18n translation", location)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
// OpenBrowser will open browser by url in different OS system
|
||||
// nolint:gosec
|
||||
func OpenBrowser(url string) error {
|
||||
|
||||
@@ -178,6 +178,7 @@ func printAppEndpoints(ctx context.Context, appName string, namespace string, f
|
||||
if skipEmptyTable && len(endpoints) == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Please access %s from the following endpoints:\n", appName)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetColWidth(100)
|
||||
table.SetHeader([]string{"Cluster", "Component", "Ref(Kind/Namespace/Name)", "Endpoint", "Inner"})
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
utilcommon "github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/common"
|
||||
@@ -199,7 +200,7 @@ func addDebugPolicy(app *v1beta1.Application) {
|
||||
|
||||
func (opt *UpCommandOptions) deployApplicationFromFile(f velacmd.Factory, cmd *cobra.Command) error {
|
||||
cli := f.Client()
|
||||
body, err := common.ReadRemoteOrLocalPath(opt.File)
|
||||
body, err := pkgUtils.ReadRemoteOrLocalPath(opt.File, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ import (
|
||||
"context"
|
||||
j "encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
@@ -284,37 +281,13 @@ func (o *DeleteOptions) DeleteComponent(io cmdutil.IOStreams) error {
|
||||
|
||||
// LoadAppFile will load vela appfile from remote URL or local file system.
|
||||
func LoadAppFile(pathOrURL string) (*api.AppFile, error) {
|
||||
body, err := ReadRemoteOrLocalPath(pathOrURL)
|
||||
body, err := utils.ReadRemoteOrLocalPath(pathOrURL, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return api.LoadFromBytes(body)
|
||||
}
|
||||
|
||||
// ReadRemoteOrLocalPath will read a path remote or locally
|
||||
func ReadRemoteOrLocalPath(pathOrURL string) ([]byte, error) {
|
||||
if pathOrURL == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
var body []byte
|
||||
var err error
|
||||
if utils.IsValidURL(pathOrURL) {
|
||||
body, err = common.HTTPGetWithOption(context.Background(), pathOrURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = localSave(pathOrURL, body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
body, err = os.ReadFile(filepath.Clean(pathOrURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// IsAppfile check if a file is Appfile format or application format, return true if it's appfile, false means application object
|
||||
func IsAppfile(body []byte) bool {
|
||||
if j.Valid(body) {
|
||||
@@ -333,25 +306,6 @@ func IsAppfile(body []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func localSave(url string, body []byte) error {
|
||||
var name string
|
||||
ext := filepath.Ext(url)
|
||||
switch ext {
|
||||
case ".json":
|
||||
name = "vela.json"
|
||||
case ".yaml", ".yml":
|
||||
name = "vela.yaml"
|
||||
default:
|
||||
if j.Valid(body) {
|
||||
name = "vela.json"
|
||||
} else {
|
||||
name = "vela.yaml"
|
||||
}
|
||||
}
|
||||
//nolint:gosec
|
||||
return os.WriteFile(name, body, 0644)
|
||||
}
|
||||
|
||||
// ExportFromAppFile exports Application from appfile object
|
||||
func (o *AppfileOptions) ExportFromAppFile(app *api.AppFile, namespace string, quiet bool, c common.Args) (*BuildResult, []byte, error) {
|
||||
tm, err := template.Load(namespace, c)
|
||||
|
||||
@@ -15,23 +15,3 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
"github.com/oam-dev/kubevela/references/appfile"
|
||||
"github.com/oam-dev/kubevela/references/appfile/api"
|
||||
)
|
||||
|
||||
// BuildRun will build application and deploy from Appfile
|
||||
func BuildRun(ctx context.Context, app *api.Application, client client.Client, namespace string, io util.IOStreams) error {
|
||||
o, err := app.ConvertToApplication(namespace, io, app.Tm, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return appfile.Run(ctx, client, o, nil)
|
||||
}
|
||||
|
||||
@@ -22,14 +22,12 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/definition"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
commontypes "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
@@ -38,8 +36,10 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/cue"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
"github.com/oam-dev/kubevela/pkg/definition"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
util2 "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -50,16 +50,42 @@ const DescriptionUndefined = "description not defined"
|
||||
|
||||
// GetCapabilitiesFromCluster will get capability from K8s cluster
|
||||
func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, error) {
|
||||
workloads, _, err := GetComponentsFromCluster(ctx, namespace, c, selector)
|
||||
caps, erl, err := GetComponentsFromCluster(ctx, namespace, c, selector)
|
||||
for _, er := range erl {
|
||||
klog.Infof("get component capability %v", er)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
traits, _, err := GetTraitsFromCluster(ctx, namespace, c, selector)
|
||||
|
||||
traits, erl, err := GetTraitsFromCluster(ctx, namespace, c, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workloads = append(workloads, traits...)
|
||||
return workloads, nil
|
||||
for _, er := range erl {
|
||||
klog.Infof("get trait capability %v", er)
|
||||
}
|
||||
caps = append(caps, traits...)
|
||||
|
||||
plcs, erl, err := GetPolicies(ctx, namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, er := range erl {
|
||||
klog.Infof("get policy capability %v", er)
|
||||
}
|
||||
caps = append(caps, plcs...)
|
||||
|
||||
wfs, erl, err := GetWorkflowSteps(ctx, namespace, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, er := range erl {
|
||||
klog.Infof("get workflow step capability %v", er)
|
||||
}
|
||||
caps = append(caps, wfs...)
|
||||
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
// GetNamespacedCapabilitiesFromCluster will get capability from K8s cluster in the specified namespace and default namespace
|
||||
@@ -297,6 +323,7 @@ func HandleDefinition(name, crdName string, annotation, labels map[string]string
|
||||
}
|
||||
tmp.CrdName = crdName
|
||||
tmp.Description = GetDescription(annotation)
|
||||
tmp.Example = GetExample(annotation)
|
||||
tmp.Labels = labels
|
||||
return tmp, nil
|
||||
}
|
||||
@@ -314,6 +341,28 @@ func GetDescription(annotation map[string]string) string {
|
||||
return desc
|
||||
}
|
||||
|
||||
// GetExample get example markdown from annotation specified url
|
||||
func GetExample(annotation map[string]string) string {
|
||||
if annotation == nil {
|
||||
return ""
|
||||
}
|
||||
examplePath, ok := annotation[types.AnnoDefinitionExampleURL]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
fmt.Println("XXXXX", examplePath)
|
||||
if !utils.IsValidURL(examplePath) {
|
||||
fmt.Println("XXyyy", examplePath)
|
||||
return ""
|
||||
}
|
||||
data, err := common.HTTPGetWithOption(context.Background(), examplePath, nil)
|
||||
if err != nil {
|
||||
fmt.Println("XXyyy", err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// HandleTemplate will handle definition template to capability
|
||||
func HandleTemplate(in *runtime.RawExtension, schematic *commontypes.Schematic, name string, pd *packages.PackageDiscover) (types.Capability, error) {
|
||||
tmp, err := appfile.ConvertTemplateJSON2Object(name, in, schematic)
|
||||
|
||||
167
references/plugins/console.go
Normal file
167
references/plugins/console.go
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
||||
// Int64Type is int64 type
|
||||
type Int64Type = int64
|
||||
|
||||
// StringType is string type
|
||||
type StringType = string
|
||||
|
||||
// BoolType is bool type
|
||||
type BoolType = bool
|
||||
|
||||
// Reference is the struct for capability information
|
||||
type Reference interface {
|
||||
prepareParameter(tableName string, parameterList []ReferenceParameter) string
|
||||
}
|
||||
|
||||
// FromCluster is the struct for input Namespace
|
||||
type FromCluster struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Rev int64 `json:"revision"`
|
||||
PD *packages.PackageDiscover
|
||||
}
|
||||
|
||||
// FromLocal is the struct for input Definition Path
|
||||
type FromLocal struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// ConsoleReference is the struct for capability information in console
|
||||
type ConsoleReference struct {
|
||||
ParseReference
|
||||
TableName string `json:"tableName"`
|
||||
TableObject *tablewriter.Table `json:"tableObject"`
|
||||
}
|
||||
|
||||
// BaseOpenAPIV3Template is Standard OpenAPIV3 Template
|
||||
var BaseOpenAPIV3Template = `{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "definition-parameter",
|
||||
"version": "1.0"
|
||||
},
|
||||
"paths": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"parameter": %s
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// ReferenceParameter is the parameter section of CUE template
|
||||
type ReferenceParameter struct {
|
||||
types.Parameter `json:",inline,omitempty"`
|
||||
// PrintableType is same to `parameter.Type` which could be printable
|
||||
PrintableType string `json:"printableType"`
|
||||
}
|
||||
|
||||
// ReferenceParameterTable stores the information of a bunch of ReferenceParameter in a table style
|
||||
type ReferenceParameterTable struct {
|
||||
Name string
|
||||
Parameters []ReferenceParameter
|
||||
Depth *int
|
||||
}
|
||||
|
||||
var commonRefs []CommonReference
|
||||
|
||||
// GenerateCUETemplateProperties get all properties of a capability
|
||||
func (ref *ConsoleReference) GenerateCUETemplateProperties(capability *types.Capability, pd *packages.PackageDiscover) (string, []ConsoleReference, error) {
|
||||
ref.DisplayFormat = "console"
|
||||
capName := capability.Name
|
||||
|
||||
cueValue, err := common.GetCUEParameterValue(capability.CueTemplate, pd)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to retrieve `parameters` value from %s with err: %w", capName, err)
|
||||
}
|
||||
var defaultDepth = 0
|
||||
doc, console, err := ref.parseParameters(capName, cueValue, Specification, defaultDepth, false)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return doc, console, nil
|
||||
}
|
||||
|
||||
// GenerateTerraformCapabilityProperties generates Capability properties for Terraform ComponentDefinition in Cli console
|
||||
func (ref *ConsoleReference) GenerateTerraformCapabilityProperties(capability types.Capability) ([]ConsoleReference, error) {
|
||||
var references []ConsoleReference
|
||||
|
||||
variableTables, _, err := ref.parseTerraformCapabilityParameters(capability)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, t := range variableTables {
|
||||
references = append(references, ref.prepareConsoleParameter(t.Name, t.Parameters, types.TerraformCategory))
|
||||
}
|
||||
return references, nil
|
||||
}
|
||||
|
||||
// Show will show capability reference in console
|
||||
func (ref *ConsoleReference) Show(ctx context.Context, c common.Args, ioStreams cmdutil.IOStreams, capabilityName string, ns string, rev int64) error {
|
||||
caps, err := ref.getCapabilities(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(caps) < 1 {
|
||||
return fmt.Errorf("no capability found with name %s namespace %s", capabilityName, ns)
|
||||
}
|
||||
capability := &caps[0]
|
||||
var propertyConsole []ConsoleReference
|
||||
switch capability.Category {
|
||||
case types.CUECategory:
|
||||
var pd *packages.PackageDiscover
|
||||
if ref.Remote != nil {
|
||||
pd = ref.Remote.PD
|
||||
}
|
||||
_, propertyConsole, err = ref.GenerateCUETemplateProperties(capability, pd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.TerraformCategory:
|
||||
propertyConsole, err = ref.GenerateTerraformCapabilityProperties(*capability)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.HelmCategory, types.KubeCategory:
|
||||
_, propertyConsole, err = ref.GenerateHelmAndKubeProperties(ctx, capability)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupport capability category %s", capability.Category)
|
||||
}
|
||||
|
||||
for _, p := range propertyConsole {
|
||||
ioStreams.Info(p.TableName)
|
||||
p.TableObject.Render()
|
||||
ioStreams.Info("\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
75
references/plugins/convert.go
Normal file
75
references/plugins/convert.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
// ParseCapabilityFromUnstructured will convert Unstructured to Capability
|
||||
func ParseCapabilityFromUnstructured(mapper discoverymapper.DiscoveryMapper, obj unstructured.Unstructured) (types.Capability, error) {
|
||||
var err error
|
||||
switch obj.GetKind() {
|
||||
case "ComponentDefinition":
|
||||
var cd v1beta1.ComponentDefinition
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &cd)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
var workloadDefinitionRef string
|
||||
if cd.Spec.Workload.Type != "" {
|
||||
workloadDefinitionRef = cd.Spec.Workload.Type
|
||||
} else if mapper != nil {
|
||||
ref, err := util.ConvertWorkloadGVK2Definition(mapper, cd.Spec.Workload.Definition)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
workloadDefinitionRef = ref.Name
|
||||
}
|
||||
return HandleDefinition(cd.Name, workloadDefinitionRef, cd.Annotations, cd.Labels, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic, nil)
|
||||
case "TraitDefinition":
|
||||
var td v1beta1.TraitDefinition
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &td)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Labels, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic, nil)
|
||||
case "PolicyDefinition":
|
||||
var pd v1beta1.PolicyDefinition
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &pd)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(pd.Name, pd.Spec.Reference.Name, pd.Annotations, pd.Labels, nil, types.TypePolicy, nil, pd.Spec.Schematic, nil)
|
||||
case "WorkflowStepDefinition":
|
||||
var pd v1beta1.WorkflowStepDefinition
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &pd)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(pd.Name, pd.Spec.Reference.Name, pd.Annotations, pd.Labels, nil, types.TypeWorkflowStep, nil, pd.Spec.Schematic, nil)
|
||||
}
|
||||
return types.Capability{}, fmt.Errorf("unknown definition Type %s", obj.GetKind())
|
||||
}
|
||||
14
references/plugins/def-doc/component/alibaba-ack.eg.md
Normal file
14
references/plugins/def-doc/component/alibaba-ack.eg.md
Normal file
@@ -0,0 +1,14 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: ack-cloud-source
|
||||
spec:
|
||||
components:
|
||||
- name: ack-cluster
|
||||
type: alibaba-ack
|
||||
properties:
|
||||
writeConnectionSecretToRef:
|
||||
name: ack-conn
|
||||
namespace: vela-system
|
||||
```
|
||||
13
references/plugins/def-doc/component/alibaba-eip.eg.md
Normal file
13
references/plugins/def-doc/component/alibaba-eip.eg.md
Normal file
@@ -0,0 +1,13 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: provision-cloud-resource-eip
|
||||
spec:
|
||||
components:
|
||||
- name: sample-eip
|
||||
type: alibaba-eip
|
||||
properties:
|
||||
writeConnectionSecretToRef:
|
||||
name: eip-conn
|
||||
```
|
||||
15
references/plugins/def-doc/component/alibaba-oss.eg.md
Normal file
15
references/plugins/def-doc/component/alibaba-oss.eg.md
Normal file
@@ -0,0 +1,15 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: oss-cloud-source
|
||||
spec:
|
||||
components:
|
||||
- name: sample-oss
|
||||
type: alibaba-oss
|
||||
properties:
|
||||
bucket: vela-website
|
||||
acl: private
|
||||
writeConnectionSecretToRef:
|
||||
name: oss-conn
|
||||
```
|
||||
16
references/plugins/def-doc/component/alibaba-rds.eg.md
Normal file
16
references/plugins/def-doc/component/alibaba-rds.eg.md
Normal file
@@ -0,0 +1,16 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: rds-cloud-source
|
||||
spec:
|
||||
components:
|
||||
- name: sample-db
|
||||
type: alibaba-rds
|
||||
properties:
|
||||
instance_name: sample-db
|
||||
account_name: oamtest
|
||||
password: U34rfwefwefffaked
|
||||
writeConnectionSecretToRef:
|
||||
name: db-conn
|
||||
```
|
||||
16
references/plugins/def-doc/component/alibaba-redis.eg.md
Normal file
16
references/plugins/def-doc/component/alibaba-redis.eg.md
Normal file
@@ -0,0 +1,16 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: redis-cloud-source
|
||||
spec:
|
||||
components:
|
||||
- name: sample-redis
|
||||
type: alibaba-redis
|
||||
properties:
|
||||
instance_name: oam-redis
|
||||
account_name: oam
|
||||
password: Xyfff83jfewGGfaked
|
||||
writeConnectionSecretToRef:
|
||||
name: redis-conn
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-sls-project-sample
|
||||
spec:
|
||||
components:
|
||||
- name: sample-sls-project
|
||||
type: alibaba-sls-project
|
||||
properties:
|
||||
name: kubevela-1112
|
||||
description: "Managed by KubeVela"
|
||||
|
||||
writeConnectionSecretToRef:
|
||||
name: sls-project-conn
|
||||
```
|
||||
18
references/plugins/def-doc/component/alibaba-sls-store.eg.md
Normal file
18
references/plugins/def-doc/component/alibaba-sls-store.eg.md
Normal file
@@ -0,0 +1,18 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-sls-store-sample
|
||||
spec:
|
||||
components:
|
||||
- name: sample-sls-store
|
||||
type: alibaba-sls-store
|
||||
properties:
|
||||
store_name: kubevela-1111
|
||||
store_retention_period: 30
|
||||
store_shard_count: 2
|
||||
store_max_split_shard_count: 2
|
||||
|
||||
writeConnectionSecretToRef:
|
||||
name: sls-store-conn
|
||||
```
|
||||
14
references/plugins/def-doc/component/alibaba-vpc.eg.md
Normal file
14
references/plugins/def-doc/component/alibaba-vpc.eg.md
Normal file
@@ -0,0 +1,14 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-vpc-sample
|
||||
spec:
|
||||
components:
|
||||
- name: sample-vpc
|
||||
type: alibaba-vpc
|
||||
properties:
|
||||
vpc_cidr: "172.16.0.0/12"
|
||||
writeConnectionSecretToRef:
|
||||
name: vpc-conn
|
||||
```
|
||||
16
references/plugins/def-doc/component/aws-s3.eg.md
Normal file
16
references/plugins/def-doc/component/aws-s3.eg.md
Normal file
@@ -0,0 +1,16 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: s3-cloud-source
|
||||
spec:
|
||||
components:
|
||||
- name: sample-s3
|
||||
type: aws-s3
|
||||
properties:
|
||||
bucket: vela-website-20211019
|
||||
acl: private
|
||||
|
||||
writeConnectionSecretToRef:
|
||||
name: s3-conn
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: mariadb-backend
|
||||
spec:
|
||||
components:
|
||||
- name: mariadb-backend
|
||||
type: azure-database-mariadb
|
||||
properties:
|
||||
resource_group: "kubevela-group"
|
||||
location: "West Europe"
|
||||
server_name: "kubevela"
|
||||
db_name: "backend"
|
||||
username: "acctestun"
|
||||
password: "H@Sh1CoR3!Faked"
|
||||
writeConnectionSecretToRef:
|
||||
name: azure-db-conn
|
||||
namespace: vela-system
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: storage-account-dev
|
||||
spec:
|
||||
components:
|
||||
- name: storage-account-dev
|
||||
type: azure-storage-account
|
||||
properties:
|
||||
create_rsg: false
|
||||
resource_group_name: "weursgappdev01"
|
||||
location: "West Europe"
|
||||
name: "appdev01"
|
||||
tags: |
|
||||
{
|
||||
ApplicationName = "Application01"
|
||||
Terraform = "Yes"
|
||||
}
|
||||
static_website: |
|
||||
[{
|
||||
index_document = "index.html"
|
||||
error_404_document = "index.html"
|
||||
}]
|
||||
|
||||
writeConnectionSecretToRef:
|
||||
name: storage-account-dev
|
||||
namespace: vela-system
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: image-dev
|
||||
namespace: vela-system
|
||||
labels:
|
||||
"app.oam.dev/source-of-truth": "from-inner-system"
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "config-image-registry"
|
||||
project: abc
|
||||
spec:
|
||||
components:
|
||||
- name: image-dev
|
||||
type: config-image-registry
|
||||
properties:
|
||||
registry: "registry.cn-beijing.aliyuncs.com"
|
||||
auth:
|
||||
username: "my-username"
|
||||
password: "my-password"
|
||||
email: "a@gmail.com"
|
||||
```
|
||||
15
references/plugins/def-doc/component/cron-task.eg.md
Normal file
15
references/plugins/def-doc/component/cron-task.eg.md
Normal file
@@ -0,0 +1,15 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cron-worker
|
||||
spec:
|
||||
components:
|
||||
- name: mytask
|
||||
type: cron-task
|
||||
properties:
|
||||
image: perl
|
||||
count: 10
|
||||
cmd: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
|
||||
schedule: "*/1 * * * *"
|
||||
```
|
||||
48
references/plugins/def-doc/component/daemon.eg.md
Normal file
48
references/plugins/def-doc/component/daemon.eg.md
Normal file
@@ -0,0 +1,48 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: addon-node-exporter
|
||||
namespace: vela-system
|
||||
spec:
|
||||
components:
|
||||
- name: node-exporter
|
||||
type: daemon
|
||||
properties:
|
||||
image: prom/node-exporter
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumeMounts:
|
||||
hostPath:
|
||||
- mountPath: /host/sys
|
||||
mountPropagation: HostToContainer
|
||||
name: sys
|
||||
path: /sys
|
||||
readOnly: true
|
||||
- mountPath: /host/root
|
||||
mountPropagation: HostToContainer
|
||||
name: root
|
||||
path: /
|
||||
readOnly: true
|
||||
traits:
|
||||
- properties:
|
||||
args:
|
||||
- --path.sysfs=/host/sys
|
||||
- --path.rootfs=/host/root
|
||||
- --no-collector.wifi
|
||||
- --no-collector.hwmon
|
||||
- --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/)
|
||||
- --collector.netclass.ignored-devices=^(veth.*)$
|
||||
type: command
|
||||
- properties:
|
||||
annotations:
|
||||
prometheus.io/path: /metrics
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/scrape: "true"
|
||||
port:
|
||||
- 9100
|
||||
type: expose
|
||||
- properties:
|
||||
cpu: 0.1
|
||||
memory: 250Mi
|
||||
type: resource
|
||||
```
|
||||
25
references/plugins/def-doc/component/k8s-objects.eg.md
Normal file
25
references/plugins/def-doc/component/k8s-objects.eg.md
Normal file
@@ -0,0 +1,25 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-raw
|
||||
spec:
|
||||
components:
|
||||
- name: myjob
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: pi
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: pi
|
||||
image: perl
|
||||
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
|
||||
restartPolicy: Never
|
||||
backoffLimit: 4
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
|---------|-------------|-----------------------|----------|---------|
|
||||
| objects | A slice of Kubernetes resource manifests | [][Kubernetes-Objects](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/) | true | |
|
||||
23
references/plugins/def-doc/component/ref-objects.eg.md
Normal file
23
references/plugins/def-doc/component/ref-objects.eg.md
Normal file
@@ -0,0 +1,23 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: ref-objects-example
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: image-pull-secrets
|
||||
type: ref-objects
|
||||
properties:
|
||||
objects:
|
||||
- resource: secret
|
||||
name: image-credential-to-copy
|
||||
policies:
|
||||
- name: topology-hangzhou-clusters
|
||||
type: topology
|
||||
properties:
|
||||
clusterLabelSelector:
|
||||
region: hangzhou
|
||||
```
|
||||
|
||||
You can refer to the [detail docs](https://kubevela.io/docs/end-user/components/ref-objects) about ref-objects.
|
||||
14
references/plugins/def-doc/component/task.eg.md
Normal file
14
references/plugins/def-doc/component/task.eg.md
Normal file
@@ -0,0 +1,14 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-worker
|
||||
spec:
|
||||
components:
|
||||
- name: mytask
|
||||
type: task
|
||||
properties:
|
||||
image: perl
|
||||
count: 10
|
||||
cmd: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
|
||||
```
|
||||
25
references/plugins/def-doc/component/webservice.eg.md
Normal file
25
references/plugins/def-doc/component/webservice.eg.md
Normal file
@@ -0,0 +1,25 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: website
|
||||
spec:
|
||||
components:
|
||||
- name: frontend
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/testapp:v1
|
||||
cmd: ["node", "server.js"]
|
||||
ports:
|
||||
- port: 8080
|
||||
expose: true
|
||||
cpu: "0.1"
|
||||
env:
|
||||
- name: FOO
|
||||
value: bar
|
||||
- name: FOO
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: bar
|
||||
key: bar
|
||||
```
|
||||
15
references/plugins/def-doc/component/worker.eg.md
Normal file
15
references/plugins/def-doc/component/worker.eg.md
Normal file
@@ -0,0 +1,15 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-worker
|
||||
spec:
|
||||
components:
|
||||
- name: myworker
|
||||
type: worker
|
||||
properties:
|
||||
image: "busybox"
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
```
|
||||
21
references/plugins/def-doc/policy/apply-once.eg.md
Normal file
21
references/plugins/def-doc/policy/apply-once.eg.md
Normal file
@@ -0,0 +1,21 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: apply-once-app
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/hello-world
|
||||
traits:
|
||||
- type: scaler
|
||||
properties:
|
||||
replicas: 1
|
||||
policies:
|
||||
- name: apply-once
|
||||
type: apply-once
|
||||
properties:
|
||||
enable: true
|
||||
```
|
||||
50
references/plugins/def-doc/policy/garbage-collect.eg.md
Normal file
50
references/plugins/def-doc/policy/garbage-collect.eg.md
Normal file
@@ -0,0 +1,50 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: first-vela-app
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: ingress-1-20
|
||||
properties:
|
||||
domain: testsvc.example.com
|
||||
http:
|
||||
"/": 8000
|
||||
policies:
|
||||
- name: keep-legacy-resource
|
||||
type: garbage-collect
|
||||
properties:
|
||||
keepLegacyResource: true
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: garbage-collect-app
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world-new
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/hello-world
|
||||
traits:
|
||||
- type: expose
|
||||
properties:
|
||||
port: [8000]
|
||||
policies:
|
||||
- name: garbage-collect
|
||||
type: garbage-collect
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
traitTypes:
|
||||
- expose
|
||||
strategy: onAppDelete
|
||||
```
|
||||
102
references/plugins/def-doc/policy/override.eg.md
Normal file
102
references/plugins/def-doc/policy/override.eg.md
Normal file
@@ -0,0 +1,102 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: deploy-with-override
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: nginx-with-override
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
policies:
|
||||
- name: topology-hangzhou-clusters
|
||||
type: topology
|
||||
properties:
|
||||
clusterLabelSelector:
|
||||
region: hangzhou
|
||||
- name: topology-local
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["local"]
|
||||
namespace: examples-alternative
|
||||
- name: override-nginx-legacy-image
|
||||
type: override
|
||||
properties:
|
||||
components:
|
||||
- name: nginx-with-override
|
||||
properties:
|
||||
image: nginx:1.20
|
||||
- name: override-high-availability
|
||||
type: override
|
||||
properties:
|
||||
components:
|
||||
- type: webservice
|
||||
traits:
|
||||
- type: scaler
|
||||
properties:
|
||||
replicas: 3
|
||||
workflow:
|
||||
steps:
|
||||
- type: deploy
|
||||
name: deploy-local
|
||||
properties:
|
||||
policies: ["topology-local"]
|
||||
- type: deploy
|
||||
name: deploy-hangzhou
|
||||
properties:
|
||||
policies: ["topology-hangzhou-clusters", "override-nginx-legacy-image", "override-high-availability"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: advance-override
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: nginx-advance-override-legacy
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx:1.20
|
||||
- name: nginx-advance-override-latest
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
policies:
|
||||
- name: topology-hangzhou-clusters
|
||||
type: topology
|
||||
properties:
|
||||
clusterLabelSelector:
|
||||
region: hangzhou
|
||||
- name: topology-local
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["local"]
|
||||
namespace: examples-alternative
|
||||
- name: override-nginx-legacy
|
||||
type: override
|
||||
properties:
|
||||
selector: ["nginx-advance-override-legacy"]
|
||||
- name: override-nginx-latest
|
||||
type: override
|
||||
properties:
|
||||
selector: ["nginx-advance-override-latest", "nginx-advance-override-stable"]
|
||||
components:
|
||||
- name: nginx-advance-override-stable
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx:stable
|
||||
workflow:
|
||||
steps:
|
||||
- type: deploy
|
||||
name: deploy-local
|
||||
properties:
|
||||
policies: ["topology-local", "override-nginx-legacy"]
|
||||
- type: deploy
|
||||
name: deploy-hangzhou
|
||||
properties:
|
||||
policies: ["topology-hangzhou-clusters", "override-nginx-latest"]
|
||||
```
|
||||
58
references/plugins/def-doc/policy/topology.eg.md
Normal file
58
references/plugins/def-doc/policy/topology.eg.md
Normal file
@@ -0,0 +1,58 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: basic-topology
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: nginx-basic
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
policies:
|
||||
- name: topology-hangzhou-clusters
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["hangzhou-1", "hangzhou-2"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: label-selector-topology
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: nginx-label-selector
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
policies:
|
||||
- name: topology-hangzhou-clusters
|
||||
type: topology
|
||||
properties:
|
||||
clusterLabelSelector:
|
||||
region: hangzhou
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: local-ns-topology
|
||||
namespace: examples
|
||||
spec:
|
||||
components:
|
||||
- name: nginx-local-ns
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
policies:
|
||||
- name: topology-local
|
||||
type: topology
|
||||
properties:
|
||||
clusters: ["local"]
|
||||
namespace: examples-alternative
|
||||
```
|
||||
20
references/plugins/def-doc/trait/annotations.eg.md
Normal file
20
references/plugins/def-doc/trait/annotations.eg.md
Normal file
@@ -0,0 +1,20 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: labels
|
||||
properties:
|
||||
"release": "stable"
|
||||
- type: annotations
|
||||
properties:
|
||||
"description": "web application"
|
||||
```
|
||||
18
references/plugins/def-doc/trait/ingress.eg.md
Normal file
18
references/plugins/def-doc/trait/ingress.eg.md
Normal file
@@ -0,0 +1,18 @@
|
||||
```yaml
|
||||
kind: Application
|
||||
metadata:
|
||||
name: first-vela-app
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: ingress
|
||||
properties:
|
||||
domain: testsvc.example.com
|
||||
http:
|
||||
"/": 8000
|
||||
```
|
||||
20
references/plugins/def-doc/trait/labels.eg.md
Normal file
20
references/plugins/def-doc/trait/labels.eg.md
Normal file
@@ -0,0 +1,20 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: labels
|
||||
properties:
|
||||
"release": "stable"
|
||||
- type: annotations
|
||||
properties:
|
||||
"description": "web application"
|
||||
```
|
||||
27
references/plugins/def-doc/trait/scaler.eg.md
Normal file
27
references/plugins/def-doc/trait/scaler.eg.md
Normal file
@@ -0,0 +1,27 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: website
|
||||
spec:
|
||||
components:
|
||||
- name: frontend
|
||||
type: webservice
|
||||
properties:
|
||||
image: nginx
|
||||
traits:
|
||||
- type: scaler
|
||||
properties:
|
||||
replicas: 2
|
||||
- type: sidecar
|
||||
properties:
|
||||
name: "sidecar-test"
|
||||
image: "fluentd"
|
||||
- name: backend
|
||||
type: worker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- sleep
|
||||
- '1000'
|
||||
```
|
||||
36
references/plugins/def-doc/trait/sidecar.eg.md
Normal file
36
references/plugins/def-doc/trait/sidecar.eg.md
Normal file
@@ -0,0 +1,36 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: vela-app-with-sidecar
|
||||
spec:
|
||||
components:
|
||||
- name: log-gen-worker
|
||||
type: worker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- >
|
||||
i=0;
|
||||
while true;
|
||||
do
|
||||
echo "$i: $(date)" >> /var/log/date.log;
|
||||
i=$((i+1));
|
||||
sleep 1;
|
||||
done
|
||||
volumes:
|
||||
- name: varlog
|
||||
mountPath: /var/log
|
||||
type: emptyDir
|
||||
traits:
|
||||
- type: sidecar
|
||||
properties:
|
||||
name: count-log
|
||||
image: busybox
|
||||
cmd: [ /bin/sh, -c, 'tail -n+1 -f /var/log/date.log']
|
||||
volumes:
|
||||
- name: varlog
|
||||
path: /var/log
|
||||
```
|
||||
79
references/plugins/embddoc.go
Normal file
79
references/plugins/embddoc.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
//go:embed def-doc
|
||||
var defdoc embed.FS
|
||||
|
||||
// DefinitionDocSamples stores the configuration yaml sample for capabilities
|
||||
var DefinitionDocSamples = map[string]string{}
|
||||
|
||||
// DefinitionDocDescription stores the description for capabilities
|
||||
var DefinitionDocDescription = map[string]string{}
|
||||
|
||||
// DefinitionDocParameters stores the parameters for capabilities, it will override the generated one
|
||||
var DefinitionDocParameters = map[string]string{}
|
||||
|
||||
const (
|
||||
suffixSample = ".eg.md"
|
||||
suffixParameter = ".param.md"
|
||||
suffixDescription = ".desc.md"
|
||||
)
|
||||
|
||||
func init() {
|
||||
err := fs.WalkDir(defdoc, "def-doc", func(path string, d fs.DirEntry, err error) error {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
switch {
|
||||
case strings.HasSuffix(d.Name(), suffixSample):
|
||||
data, err := defdoc.ReadFile(path)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "ignore this embed built-in definition sample", "path", path)
|
||||
return nil
|
||||
}
|
||||
DefinitionDocSamples[strings.TrimSuffix(d.Name(), suffixSample)] = strings.TrimSpace(string(data))
|
||||
case strings.HasSuffix(d.Name(), suffixDescription):
|
||||
data, err := defdoc.ReadFile(path)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "ignore this embed built-in definition description", "path", path)
|
||||
return nil
|
||||
}
|
||||
DefinitionDocDescription[strings.TrimSuffix(d.Name(), suffixDescription)] = strings.TrimSpace(string(data))
|
||||
case strings.HasSuffix(d.Name(), suffixParameter):
|
||||
data, err := defdoc.ReadFile(path)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "ignore this embed built-in definition parameter", "path", path)
|
||||
return nil
|
||||
}
|
||||
DefinitionDocParameters[strings.TrimSuffix(d.Name(), suffixParameter)] = strings.TrimSpace(string(data))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to read embed built-in definition documentation")
|
||||
return
|
||||
}
|
||||
}
|
||||
27
references/plugins/embddoc_test.go
Normal file
27
references/plugins/embddoc_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDcoInit(t *testing.T) {
|
||||
assert.True(t, len(DefinitionDocSamples) > 0)
|
||||
}
|
||||
@@ -16,120 +16,172 @@ limitations under the License.
|
||||
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// Language is used to define the language
|
||||
type Language string
|
||||
|
||||
const (
|
||||
// En is English, the default language
|
||||
En Language = "English"
|
||||
var (
|
||||
// En is english, the default language
|
||||
En = I18n{lang: LangEn}
|
||||
// Zh is Chinese
|
||||
Zh Language = "Chinese"
|
||||
Zh = I18n{lang: LangZh}
|
||||
)
|
||||
|
||||
const (
|
||||
// LangEn is english, the default language
|
||||
LangEn Language = "English"
|
||||
// LangZh is Chinese
|
||||
LangZh Language = "Chinese"
|
||||
)
|
||||
|
||||
// I18n will automatically get translated data
|
||||
type I18n struct {
|
||||
lang Language
|
||||
}
|
||||
|
||||
// LoadI18nData will load i18n data for the package
|
||||
func LoadI18nData(path string) {
|
||||
|
||||
log.Printf("loading i18n data from %s", path)
|
||||
data, err := utils.ReadRemoteOrLocalPath(path, false)
|
||||
if err != nil {
|
||||
log.Println("ignore using the i18n data", err)
|
||||
return
|
||||
}
|
||||
var dat = map[string]map[Language]string{}
|
||||
err = json.Unmarshal(data, &dat)
|
||||
if err != nil {
|
||||
log.Println("ignore using the i18n data", err)
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range dat {
|
||||
if _, ok := v[LangEn]; !ok {
|
||||
v[LangEn] = k
|
||||
}
|
||||
k = strings.ToLower(k)
|
||||
ed, ok := i18nDoc[k]
|
||||
if !ok {
|
||||
ed = map[Language]string{}
|
||||
}
|
||||
for sk, sv := range v {
|
||||
sv = strings.TrimSpace(sv)
|
||||
if sv == "" {
|
||||
continue
|
||||
}
|
||||
ed[sk] = sv
|
||||
}
|
||||
i18nDoc[k] = ed
|
||||
}
|
||||
}
|
||||
|
||||
// Language return the language used in i18n instance
|
||||
func (i *I18n) Language() Language {
|
||||
if i == nil || i.lang == "" {
|
||||
return En.Language()
|
||||
}
|
||||
return i.lang
|
||||
}
|
||||
|
||||
func (i *I18n) trans(str string) (string, bool) {
|
||||
dd, ok := i18nDoc[str]
|
||||
if !ok {
|
||||
return str, false
|
||||
}
|
||||
data := dd[i.lang]
|
||||
if data == "" {
|
||||
return str, true
|
||||
}
|
||||
return data, true
|
||||
}
|
||||
|
||||
// Get translate for the string
|
||||
func (i *I18n) Get(str string) string {
|
||||
if i == nil || i.lang == "" {
|
||||
return En.Get(str)
|
||||
}
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
str = strings.TrimSuffix(str, ".")
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
str = strings.TrimSuffix(str, "。")
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
raw := str
|
||||
str = strings.TrimSpace(str)
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
str = strings.ToLower(str)
|
||||
if data, ok := i.trans(str); ok {
|
||||
return data
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
// Definitions are all the words and phrases for internationalization in cli and docs
|
||||
var Definitions = map[string]map[Language]string{
|
||||
"Description": {
|
||||
Zh: "描述",
|
||||
En: "Description",
|
||||
var i18nDoc = map[string]map[Language]string{
|
||||
".": {
|
||||
LangZh: "。",
|
||||
LangEn: ".",
|
||||
},
|
||||
"Samples": {
|
||||
Zh: "示例",
|
||||
En: "Samples",
|
||||
"Description": {
|
||||
LangZh: "描述",
|
||||
LangEn: "Description",
|
||||
},
|
||||
"Examples": {
|
||||
LangZh: "示例",
|
||||
LangEn: "Examples",
|
||||
},
|
||||
"Specification": {
|
||||
Zh: "参数说明",
|
||||
En: "Specification",
|
||||
LangZh: "参数说明",
|
||||
LangEn: "Specification",
|
||||
},
|
||||
"AlibabaCloud": {
|
||||
Zh: "阿里云",
|
||||
En: "Alibaba Cloud",
|
||||
LangZh: "阿里云",
|
||||
LangEn: "Alibaba Cloud",
|
||||
},
|
||||
"AWS": {
|
||||
Zh: "AWS",
|
||||
En: "AWS",
|
||||
LangZh: "AWS",
|
||||
LangEn: "AWS",
|
||||
},
|
||||
"Azure": {
|
||||
Zh: "Azure",
|
||||
En: "Azure",
|
||||
LangZh: "Azure",
|
||||
LangEn: "Azure",
|
||||
},
|
||||
"Name": {
|
||||
Zh: "名称",
|
||||
En: "Name",
|
||||
LangZh: "名称",
|
||||
LangEn: "Name",
|
||||
},
|
||||
"Type": {
|
||||
Zh: "类型",
|
||||
En: "Type",
|
||||
LangZh: "类型",
|
||||
LangEn: "Type",
|
||||
},
|
||||
"Required": {
|
||||
Zh: "是否必须",
|
||||
En: "Required",
|
||||
LangZh: "是否必须",
|
||||
LangEn: "Required",
|
||||
},
|
||||
"Default": {
|
||||
Zh: "默认值",
|
||||
En: "Default",
|
||||
LangZh: "默认值",
|
||||
LangEn: "Default",
|
||||
},
|
||||
"WriteConnectionSecretToRefIntroduction": {
|
||||
Zh: "如果设置了 `writeConnectionSecretToRef`,一个 Kubernetes Secret 将会被创建,并且,它的数据里有这些键(key):",
|
||||
En: "If `writeConnectionSecretToRef` is set, a secret will be generated with these keys as below:",
|
||||
},
|
||||
"Outputs": {
|
||||
Zh: "输出",
|
||||
En: "Outputs",
|
||||
},
|
||||
"Properties": {
|
||||
Zh: "属性",
|
||||
En: "Properties",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_ACK_cluster": {
|
||||
Zh: "用于部署阿里云 ACK 集群的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud ACK cluster",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_Serverless_Kubernetes_(ASK)": {
|
||||
Zh: "用于部署阿里云 Serverless Kubernetes (ASK) 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud Serverless Kubernetes (ASK)",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_Elastic_IP": {
|
||||
Zh: "用于部署阿里云弹性 IP 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud Elastic IP",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_OSS_object": {
|
||||
Zh: "用于部署阿里云 OSS 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud OSS",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_RDS_object": {
|
||||
Zh: "用于部署阿里云 RDS 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud RDS",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_Redis": {
|
||||
Zh: "用于部署阿里云 Redis 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud Redis",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_SLS_Project": {
|
||||
Zh: "用于部署阿里云 SLS Project 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud SLS Project",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_SLS_Store": {
|
||||
Zh: "用于部署阿里云 SLS Store 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud SLS Store",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_VPC": {
|
||||
Zh: "用于部署阿里云 VPC 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud VPC",
|
||||
},
|
||||
"Terraform_configuration_for_Alibaba_Cloud_VSwitch": {
|
||||
Zh: "用于部署阿里云 VSwitch 的组件说明",
|
||||
En: "Terraform configuration for Alibaba Cloud VSwitch",
|
||||
},
|
||||
"Terraform_configuration_for_AWS_S3": {
|
||||
Zh: "用于部署 AWS S3 的组件说明",
|
||||
En: "Terraform configuration for AWS S3",
|
||||
},
|
||||
"Terraform_configuration_for_Azure_Database_Mariadb": {
|
||||
Zh: "用于部署 Azure mariadb 数据库的组件说明",
|
||||
En: "Terraform configuration for Azure Database Mariadb",
|
||||
},
|
||||
"Terraform_configuration_for_Azure_Blob_Storage_Account": {
|
||||
Zh: "用于部署 Azure Blob Storage 账号的的组件说明",
|
||||
En: "Terraform configuration for Azure Blob Storage Account",
|
||||
"Apply To Component Types": {
|
||||
LangZh: "适用于组件类型",
|
||||
LangEn: "Apply To Component Types",
|
||||
},
|
||||
}
|
||||
|
||||
57
references/plugins/i18n_test.go
Normal file
57
references/plugins/i18n_test.go
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
|
||||
go func() {
|
||||
svr := http.NewServeMux()
|
||||
svr.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{"Outputs":{"Chinese":"输出"}}`)
|
||||
})
|
||||
http.ListenAndServe(":65502", svr)
|
||||
}()
|
||||
time.Sleep(time.Millisecond)
|
||||
assert.Equal(t, En.Language(), Language("English"))
|
||||
assert.Equal(t, En.Get("nihaoha"), "nihaoha")
|
||||
assert.Equal(t, En.Get("AlibabaCloud"), "Alibaba Cloud")
|
||||
var ni *I18n
|
||||
assert.Equal(t, ni.Get("AlibabaCloud"), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get("AlibabaCloud."), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get("AlibabaCloud。"), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get("AlibabaCloud。 "), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get("AlibabaCloud 。 "), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get("AlibabaCloud \n "), "Alibaba Cloud")
|
||||
assert.Equal(t, ni.Get(" A\n "), "A")
|
||||
assert.Equal(t, ni.Get(" \n "), "")
|
||||
|
||||
assert.Equal(t, Zh.Language(), Language("Chinese"))
|
||||
assert.Equal(t, Zh.Get("nihaoha"), "nihaoha")
|
||||
assert.Equal(t, Zh.Get("AlibabaCloud"), "阿里云")
|
||||
|
||||
LoadI18nData("http://127.0.0.1:65502")
|
||||
assert.Equal(t, Zh.Get("Outputs"), "输出")
|
||||
}
|
||||
@@ -1,57 +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 plugins
|
||||
|
||||
import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
)
|
||||
|
||||
var (
|
||||
deployment = types.Capability{
|
||||
Name: "deployment",
|
||||
Type: types.TypeComponentDefinition,
|
||||
Parameters: []types.Parameter{
|
||||
{
|
||||
Name: "image",
|
||||
Short: "i",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
statefulset = types.Capability{
|
||||
Name: "statefulset",
|
||||
Type: types.TypeComponentDefinition,
|
||||
Parameters: []types.Parameter{
|
||||
{
|
||||
Name: "image",
|
||||
Short: "i",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
route = types.Capability{
|
||||
Name: "route",
|
||||
Type: types.TypeTrait,
|
||||
Parameters: []types.Parameter{
|
||||
{
|
||||
Name: "domain",
|
||||
Short: "d",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
313
references/plugins/markdown.go
Normal file
313
references/plugins/markdown.go
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
// MarkdownReference is the struct for capability information in
|
||||
type MarkdownReference struct {
|
||||
Filter func(types.Capability) bool
|
||||
AllInOne bool
|
||||
CustomDocHeader string
|
||||
ParseReference
|
||||
}
|
||||
|
||||
// GenerateReferenceDocs generates reference docs
|
||||
func (ref *MarkdownReference) GenerateReferenceDocs(ctx context.Context, c common.Args, baseRefPath string) error {
|
||||
caps, err := ref.getCapabilities(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pd *packages.PackageDiscover
|
||||
if ref.Remote != nil {
|
||||
pd = ref.Remote.PD
|
||||
}
|
||||
return ref.CreateMarkdown(ctx, caps, baseRefPath, false, pd)
|
||||
}
|
||||
|
||||
// CreateMarkdown creates markdown based on capabilities
|
||||
func (ref *MarkdownReference) CreateMarkdown(ctx context.Context, caps []types.Capability, baseRefPath string, catalog bool, pd *packages.PackageDiscover) error {
|
||||
|
||||
sort.Slice(caps, func(i, j int) bool {
|
||||
return caps[i].Name < caps[j].Name
|
||||
})
|
||||
|
||||
var all string
|
||||
ref.DisplayFormat = Markdown
|
||||
for _, c := range caps {
|
||||
if ref.Filter != nil && !ref.Filter(c) {
|
||||
continue
|
||||
}
|
||||
capDoc, err := ref.GenerateMarkdownForCap(ctx, c, pd, ref.AllInOne)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if baseRefPath == "" {
|
||||
fmt.Println(capDoc)
|
||||
continue
|
||||
}
|
||||
if ref.AllInOne {
|
||||
all += capDoc + "\n\n"
|
||||
continue
|
||||
}
|
||||
|
||||
refPath := baseRefPath
|
||||
if catalog {
|
||||
// catalog by capability type with folder
|
||||
refPath = filepath.Join(baseRefPath, string(c.Type))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(refPath); err != nil && os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(refPath, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
refPath = strings.TrimSuffix(refPath, "/")
|
||||
fileName := fmt.Sprintf("%s.md", c.Name)
|
||||
markdownFile := filepath.Join(refPath, fileName)
|
||||
f, err := os.OpenFile(filepath.Clean(markdownFile), os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file %s: %w", markdownFile, err)
|
||||
}
|
||||
if err = os.Truncate(markdownFile, 0); err != nil {
|
||||
return fmt.Errorf("failed to truncate file %s: %w", markdownFile, err)
|
||||
}
|
||||
|
||||
if _, err := f.WriteString(capDoc); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !ref.AllInOne {
|
||||
return nil
|
||||
}
|
||||
all = ref.CustomDocHeader + all
|
||||
if baseRefPath != "" {
|
||||
return ioutil.WriteFile(baseRefPath, []byte(all), 0600)
|
||||
}
|
||||
fmt.Println(all)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateMarkdownForCap will generate markdown for one capability
|
||||
func (ref *MarkdownReference) GenerateMarkdownForCap(ctx context.Context, c types.Capability, pd *packages.PackageDiscover, containSuffix bool) (string, error) {
|
||||
var (
|
||||
description string
|
||||
sample string
|
||||
specification string
|
||||
generatedDoc string
|
||||
err error
|
||||
)
|
||||
if c.Type != types.TypeWorkload && c.Type != types.TypeComponentDefinition && c.Type != types.TypeTrait &&
|
||||
c.Type != types.TypeWorkflowStep && c.Type != types.TypePolicy {
|
||||
return "", fmt.Errorf("type(%s) of the capability(%s) is not supported for now", c.Type, c.Name)
|
||||
}
|
||||
|
||||
capName := c.Name
|
||||
lang := ref.I18N
|
||||
capNameInTitle := ref.makeReadableTitle(capName)
|
||||
switch c.Category {
|
||||
case types.CUECategory:
|
||||
cueValue, err := common.GetCUEParameterValue(c.CueTemplate, pd)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve `parameters` value from %s with err: %w", c.Name, err)
|
||||
}
|
||||
var defaultDepth = 0
|
||||
generatedDoc, _, err = ref.parseParameters(capName, cueValue, Specification, defaultDepth, containSuffix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
case types.HelmCategory, types.KubeCategory:
|
||||
properties, _, err := ref.GenerateHelmAndKubeProperties(ctx, &c)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve `parameters` value from %s with err: %w", c.Name, err)
|
||||
}
|
||||
for _, property := range properties {
|
||||
generatedDoc += ref.getParameterString("###"+property.Name, property.Parameters, types.HelmCategory)
|
||||
}
|
||||
case types.TerraformCategory:
|
||||
generatedDoc, err = ref.GenerateTerraformCapabilityPropertiesAndOutputs(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupport category %s from capability %s", c.Category, capName)
|
||||
}
|
||||
title := fmt.Sprintf("---\ntitle: %s\n---", capNameInTitle)
|
||||
if ref.AllInOne {
|
||||
title = fmt.Sprintf("## %s", capNameInTitle)
|
||||
}
|
||||
sampleContent := c.Example
|
||||
if sampleContent == "" {
|
||||
sampleContent = DefinitionDocSamples[capName]
|
||||
}
|
||||
descriptionI18N := DefinitionDocDescription[capName]
|
||||
if descriptionI18N == "" {
|
||||
descriptionI18N = c.Description
|
||||
}
|
||||
|
||||
parameterDoc := DefinitionDocParameters[capName]
|
||||
if parameterDoc == "" {
|
||||
parameterDoc = generatedDoc
|
||||
}
|
||||
|
||||
var sharp = "##"
|
||||
exampleTitle := lang.Get(Examples)
|
||||
specificationTitle := lang.Get(Specification)
|
||||
if ref.AllInOne {
|
||||
sharp = "###"
|
||||
exampleTitle += " (" + capName + ")"
|
||||
specificationTitle += " (" + capName + ")"
|
||||
}
|
||||
description = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, lang.Get(Description), strings.TrimSpace(lang.Get(descriptionI18N)))
|
||||
if !strings.HasSuffix(description, lang.Get(".")) {
|
||||
description += lang.Get(".")
|
||||
}
|
||||
|
||||
if c.Type == types.TypeTrait {
|
||||
|
||||
description += "\n\n### " + lang.Get("Apply To Component Types") + "\n\n"
|
||||
var applyto string
|
||||
for _, ap := range c.AppliesTo {
|
||||
applyto += "- " + ap + "\n"
|
||||
}
|
||||
if applyto == "" {
|
||||
applyto = "- All/*"
|
||||
}
|
||||
description += applyto + "\n"
|
||||
}
|
||||
|
||||
if sampleContent != "" {
|
||||
sample = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, exampleTitle, sampleContent)
|
||||
}
|
||||
specification = fmt.Sprintf("\n\n%s %s\n%s", sharp, specificationTitle, parameterDoc)
|
||||
|
||||
return title + description + sample + specification, nil
|
||||
}
|
||||
|
||||
func (ref *MarkdownReference) makeReadableTitle(title string) string {
|
||||
if !strings.Contains(title, "-") {
|
||||
return strings.Title(title)
|
||||
}
|
||||
var name string
|
||||
provider := strings.Split(title, "-")[0]
|
||||
switch provider {
|
||||
case "alibaba":
|
||||
name = "AlibabaCloud"
|
||||
case "aws":
|
||||
name = "AWS"
|
||||
case "azure":
|
||||
name = "Azure"
|
||||
default:
|
||||
return strings.Title(title)
|
||||
}
|
||||
cloudResource := strings.Replace(title, provider+"-", "", 1)
|
||||
return fmt.Sprintf("%s %s", ref.I18N.Get(name), strings.ToUpper(cloudResource))
|
||||
}
|
||||
|
||||
// getParameterString prepares the table content for each property
|
||||
func (ref *MarkdownReference) getParameterString(tableName string, parameterList []ReferenceParameter, category types.CapabilityCategory) string {
|
||||
tab := fmt.Sprintf("\n\n%s\n\n", tableName)
|
||||
if tableName == "" || tableName == Specification {
|
||||
tab = "\n\n"
|
||||
}
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %s | %s \n", ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default"))
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %s | %s \n",
|
||||
strings.Repeat("-", len(ref.I18N.Get("Name"))),
|
||||
strings.Repeat("-", len(ref.I18N.Get("Description"))),
|
||||
strings.Repeat("-", len(ref.I18N.Get("Type"))),
|
||||
strings.Repeat("-", len(ref.I18N.Get("Required"))),
|
||||
strings.Repeat("-", len(ref.I18N.Get("Default"))))
|
||||
|
||||
switch category {
|
||||
case types.CUECategory:
|
||||
for _, p := range parameterList {
|
||||
if !p.Ignore {
|
||||
printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), p.PrintableType, p.Required, printableDefaultValue)
|
||||
}
|
||||
}
|
||||
case types.HelmCategory:
|
||||
for _, p := range parameterList {
|
||||
printableDefaultValue := ref.getJSONPrintableDefaultValue(p.JSONType, p.Default)
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), p.PrintableType, p.Required, printableDefaultValue)
|
||||
}
|
||||
case types.KubeCategory:
|
||||
for _, p := range parameterList {
|
||||
// Kube parameter doesn't have default value
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), p.PrintableType, p.Required, "")
|
||||
}
|
||||
case types.TerraformCategory:
|
||||
// Terraform doesn't have default value
|
||||
for _, p := range parameterList {
|
||||
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), p.PrintableType, p.Required, "")
|
||||
}
|
||||
default:
|
||||
}
|
||||
return tab
|
||||
}
|
||||
|
||||
// GenerateTerraformCapabilityPropertiesAndOutputs generates Capability properties and outputs for Terraform ComponentDefinition
|
||||
func (ref *MarkdownReference) GenerateTerraformCapabilityPropertiesAndOutputs(capability types.Capability) (string, error) {
|
||||
var references string
|
||||
|
||||
variableTables, outputsTable, err := ref.parseTerraformCapabilityParameters(capability)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, t := range variableTables {
|
||||
references += ref.getParameterString(t.Name, t.Parameters, types.CUECategory)
|
||||
}
|
||||
for _, t := range outputsTable {
|
||||
references += ref.prepareTerraformOutputs(t.Name, t.Parameters)
|
||||
}
|
||||
return references, nil
|
||||
}
|
||||
|
||||
// getParameterString prepares the table content for each property
|
||||
func (ref *MarkdownReference) prepareTerraformOutputs(tableName string, parameterList []ReferenceParameter) string {
|
||||
if len(parameterList) == 0 {
|
||||
return ""
|
||||
}
|
||||
tfdoc := fmt.Sprintf("\n\n%s\n\n", tableName)
|
||||
if tableName == "" {
|
||||
tfdoc = "\n\n"
|
||||
}
|
||||
tfdoc += fmt.Sprintf(" %s | %s \n", ref.I18N.Get("Name"), ref.I18N.Get("Description"))
|
||||
tfdoc += " ------------ | ------------- \n"
|
||||
|
||||
for _, p := range parameterList {
|
||||
tfdoc += fmt.Sprintf(" %s | %s\n", p.Name, p.Usage)
|
||||
}
|
||||
|
||||
return tfdoc
|
||||
}
|
||||
183
references/plugins/markdown_test.go
Normal file
183
references/plugins/markdown_test.go
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
func TestCreateMarkdownForCUE(t *testing.T) {
|
||||
go func() {
|
||||
svr := http.NewServeMux()
|
||||
svr.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
||||
})
|
||||
http.ListenAndServe(":65501", svr)
|
||||
}()
|
||||
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
mr := MarkdownReference{}
|
||||
mr.Local = &FromLocal{Path: "./testdata/testdef.cue"}
|
||||
capp, err := ParseLocalFile(mr.Local.Path, common.Args{})
|
||||
assert.NoError(t, err)
|
||||
got, err := mr.GenerateMarkdownForCap(context.Background(), *capp, nil, false)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(got)
|
||||
assert.Contains(t, got, "A test key")
|
||||
assert.Contains(t, got, "title: Testdef")
|
||||
assert.Contains(t, got, "K8s-objects allow users to specify raw K8s objects in properties")
|
||||
assert.Contains(t, got, "Examples")
|
||||
assert.Contains(t, got, "Hello, examples/applications/create-namespace.yaml!")
|
||||
|
||||
mr.Local = &FromLocal{Path: "./testdata/testdeftrait.cue"}
|
||||
capp, err = ParseLocalFile(mr.Local.Path, common.Args{})
|
||||
assert.NoError(t, err)
|
||||
got, err = mr.GenerateMarkdownForCap(context.Background(), *capp, nil, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, got, "Specify the hostAliases to add")
|
||||
assert.Contains(t, got, "title: Testdeftrait")
|
||||
assert.Contains(t, got, "Add host aliases on K8s pod for your workload which follows the pod spec in path 'spec.template'.")
|
||||
}
|
||||
|
||||
func TestCreateMarkdown(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ref := &MarkdownReference{}
|
||||
ref.I18N = &En
|
||||
|
||||
refZh := &MarkdownReference{}
|
||||
refZh.I18N = &Zh
|
||||
|
||||
workloadName := "workload1"
|
||||
traitName := "trait1"
|
||||
scopeName := "scope1"
|
||||
workloadName2 := "workload2"
|
||||
|
||||
workloadCueTemplate := `
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
}
|
||||
`
|
||||
traitCueTemplate := `
|
||||
parameter: {
|
||||
replicas: int
|
||||
}
|
||||
`
|
||||
|
||||
configuration := `
|
||||
resource "alicloud_oss_bucket" "bucket-acl" {
|
||||
bucket = var.bucket
|
||||
acl = var.acl
|
||||
}
|
||||
|
||||
output "BUCKET_NAME" {
|
||||
value = "${alicloud_oss_bucket.bucket-acl.bucket}.${alicloud_oss_bucket.bucket-acl.extranet_endpoint}"
|
||||
}
|
||||
|
||||
variable "bucket" {
|
||||
description = "OSS bucket name"
|
||||
default = "vela-website"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "acl" {
|
||||
description = "OSS bucket ACL, supported 'private', 'public-read', 'public-read-write'"
|
||||
default = "private"
|
||||
type = string
|
||||
}
|
||||
`
|
||||
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
ref *MarkdownReference
|
||||
capabilities []types.Capability
|
||||
want error
|
||||
}{
|
||||
"WorkloadTypeAndTraitCapability": {
|
||||
reason: "valid capabilities",
|
||||
ref: ref,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: workloadName,
|
||||
Type: types.TypeWorkload,
|
||||
CueTemplate: workloadCueTemplate,
|
||||
Category: types.CUECategory,
|
||||
},
|
||||
{
|
||||
Name: traitName,
|
||||
Type: types.TypeTrait,
|
||||
CueTemplate: traitCueTemplate,
|
||||
Category: types.CUECategory,
|
||||
},
|
||||
{
|
||||
Name: workloadName2,
|
||||
TerraformConfiguration: configuration,
|
||||
Type: types.TypeWorkload,
|
||||
Category: types.TerraformCategory,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
"ScopeTypeCapability": {
|
||||
reason: "invalid capabilities",
|
||||
ref: ref,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: scopeName,
|
||||
Type: types.TypeScope,
|
||||
},
|
||||
},
|
||||
want: fmt.Errorf("type(scope) of the capability(scope1) is not supported for now"),
|
||||
},
|
||||
"TerraformCapabilityInChinese": {
|
||||
reason: "terraform capability",
|
||||
ref: refZh,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: workloadName2,
|
||||
TerraformConfiguration: configuration,
|
||||
Type: types.TypeWorkload,
|
||||
Category: types.TerraformCategory,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := tc.ref.CreateMarkdown(ctx, tc.capabilities, RefTestDir, false, nil)
|
||||
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nCreateMakrdown(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
536
references/plugins/parser.go
Normal file
536
references/plugins/parser.go
Normal file
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/ast"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
pkgdef "github.com/oam-dev/kubevela/pkg/definition"
|
||||
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/terraform"
|
||||
)
|
||||
|
||||
// ParseReference is used to include the common function `parseParameter`
|
||||
type ParseReference struct {
|
||||
Client client.Client
|
||||
I18N *I18n `json:"i18n"`
|
||||
Remote *FromCluster `json:"remote"`
|
||||
Local *FromLocal `json:"local"`
|
||||
DefinitionName string `json:"definitionName"`
|
||||
DisplayFormat string
|
||||
}
|
||||
|
||||
func (ref *ParseReference) getCapabilities(ctx context.Context, c common.Args) ([]types.Capability, error) {
|
||||
var (
|
||||
caps []types.Capability
|
||||
pd *packages.PackageDiscover
|
||||
)
|
||||
switch {
|
||||
case ref.Local != nil:
|
||||
lcap, err := ParseLocalFile(ref.Local.Path, c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get capability from local file %s: %w", ref.DefinitionName, err)
|
||||
}
|
||||
caps = append(caps, *lcap)
|
||||
case ref.Remote != nil:
|
||||
config, err := c.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pd, err = packages.NewPackageDiscover(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref.Remote.PD = pd
|
||||
if ref.DefinitionName == "" {
|
||||
caps, err = LoadAllInstalledCapability("default", c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get all capabilityes: %w", err)
|
||||
}
|
||||
} else {
|
||||
var rcap *types.Capability
|
||||
if ref.Remote.Rev == 0 {
|
||||
rcap, err = GetCapabilityByName(ctx, c, ref.DefinitionName, ref.Remote.Namespace, pd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get capability %s: %w", ref.DefinitionName, err)
|
||||
}
|
||||
} else {
|
||||
rcap, err = GetCapabilityFromDefinitionRevision(ctx, c, pd, ref.Remote.Namespace, ref.DefinitionName, ref.Remote.Rev)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get revision %v of capability %s: %w", ref.Remote.Rev, ref.DefinitionName, err)
|
||||
}
|
||||
}
|
||||
caps = []types.Capability{*rcap}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to get capability %s without namespace or local filepath", ref.DefinitionName)
|
||||
}
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
func (ref *ParseReference) prettySentence(s string) string {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return ""
|
||||
}
|
||||
return ref.I18N.Get(s) + ref.I18N.Get(".")
|
||||
}
|
||||
|
||||
// prepareConsoleParameter prepares the table content for each property
|
||||
func (ref *ParseReference) prepareConsoleParameter(tableName string, parameterList []ReferenceParameter, category types.CapabilityCategory) ConsoleReference {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetColWidth(100)
|
||||
table.SetHeader([]string{ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default")})
|
||||
switch category {
|
||||
case types.CUECategory:
|
||||
for _, p := range parameterList {
|
||||
if !p.Ignore {
|
||||
printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
|
||||
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue)})
|
||||
}
|
||||
}
|
||||
case types.HelmCategory, types.KubeCategory:
|
||||
for _, p := range parameterList {
|
||||
printableDefaultValue := ref.getJSONPrintableDefaultValue(p.JSONType, p.Default)
|
||||
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue)})
|
||||
}
|
||||
case types.TerraformCategory:
|
||||
// Terraform doesn't have default value
|
||||
for _, p := range parameterList {
|
||||
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ""})
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
return ConsoleReference{TableName: tableName, TableObject: table}
|
||||
}
|
||||
|
||||
// parseParameters parses every parameter
|
||||
func (ref *ParseReference) parseParameters(capName string, paraValue cue.Value, paramKey string, depth int, containSuffix bool) (string, []ConsoleReference, error) {
|
||||
var doc string
|
||||
var console []ConsoleReference
|
||||
var params []ReferenceParameter
|
||||
var suffixTitle = " (" + capName + ")"
|
||||
var suffixRef = "-" + strings.ToLower(capName)
|
||||
if !containSuffix || capName == "" {
|
||||
suffixTitle = ""
|
||||
suffixRef = ""
|
||||
}
|
||||
switch paraValue.Kind() {
|
||||
case cue.StructKind:
|
||||
arguments, err := paraValue.Struct()
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("arguments not defined as struct %w", err)
|
||||
}
|
||||
if arguments.Len() == 0 {
|
||||
var param ReferenceParameter
|
||||
param.Name = "\\-"
|
||||
param.Required = true
|
||||
tl := paraValue.Template()
|
||||
if tl != nil { // is map type
|
||||
param.PrintableType = fmt.Sprintf("map[string]%s", tl("").IncompleteKind().String())
|
||||
} else {
|
||||
param.PrintableType = "{}"
|
||||
}
|
||||
params = append(params, param)
|
||||
}
|
||||
|
||||
for i := 0; i < arguments.Len(); i++ {
|
||||
var param ReferenceParameter
|
||||
fi := arguments.Field(i)
|
||||
if fi.IsDefinition {
|
||||
continue
|
||||
}
|
||||
val := fi.Value
|
||||
name := fi.Name
|
||||
param.Name = name
|
||||
param.Required = !fi.IsOptional
|
||||
if def, ok := val.Default(); ok && def.IsConcrete() {
|
||||
param.Default = velacue.GetDefault(def)
|
||||
}
|
||||
param.Short, param.Usage, param.Alias, param.Ignore = velacue.RetrieveComments(val)
|
||||
param.Type = val.IncompleteKind()
|
||||
switch val.IncompleteKind() {
|
||||
case cue.StructKind:
|
||||
if subField, err := val.Struct(); err == nil && subField.Len() == 0 { // err cannot be not nil,so ignore it
|
||||
if mapValue, ok := val.Elem(); ok {
|
||||
// In the future we could recursively call to support complex map-value(struct or list)
|
||||
source, converted := mapValue.Source().(*ast.Ident)
|
||||
if converted && len(source.Name) != 0 {
|
||||
param.PrintableType = fmt.Sprintf("map[string]%s", source.Name)
|
||||
} else {
|
||||
param.PrintableType = fmt.Sprintf("map[string]%s", mapValue.IncompleteKind().String())
|
||||
}
|
||||
} else {
|
||||
return "", nil, fmt.Errorf("failed to got Map kind from %s", param.Name)
|
||||
}
|
||||
} else {
|
||||
subDoc, subConsole, err := ref.parseParameters(capName, val, name, depth+1, containSuffix)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
param.PrintableType = fmt.Sprintf("[%s](#%s%s)", name, strings.ToLower(name), suffixRef)
|
||||
doc += subDoc
|
||||
console = append(console, subConsole...)
|
||||
}
|
||||
case cue.ListKind:
|
||||
elem, success := val.Elem()
|
||||
if !success {
|
||||
// fail to get elements, use the value of ListKind to be the type
|
||||
param.Type = val.Kind()
|
||||
param.PrintableType = val.IncompleteKind().String()
|
||||
break
|
||||
}
|
||||
switch elem.Kind() {
|
||||
case cue.StructKind:
|
||||
param.PrintableType = fmt.Sprintf("[[]%s](#%s%s)", name, strings.ToLower(name), suffixRef)
|
||||
subDoc, subConsole, err := ref.parseParameters(capName, elem, name, depth+1, containSuffix)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
doc += subDoc
|
||||
console = append(console, subConsole...)
|
||||
default:
|
||||
param.Type = elem.Kind()
|
||||
param.PrintableType = fmt.Sprintf("[]%s", elem.IncompleteKind().String())
|
||||
}
|
||||
default:
|
||||
param.PrintableType = param.Type.String()
|
||||
}
|
||||
params = append(params, param)
|
||||
}
|
||||
default:
|
||||
//
|
||||
}
|
||||
|
||||
switch ref.DisplayFormat {
|
||||
case Markdown, "":
|
||||
// markdown defines the contents that display in web
|
||||
var tableName string
|
||||
if paramKey != Specification {
|
||||
length := depth + 3
|
||||
if length >= 5 {
|
||||
length = 5
|
||||
}
|
||||
tableName = fmt.Sprintf("%s %s%s", strings.Repeat("#", length), paramKey, suffixTitle)
|
||||
}
|
||||
mref := MarkdownReference{}
|
||||
mref.I18N = ref.I18N
|
||||
doc = mref.getParameterString(tableName, params, types.CUECategory) + doc
|
||||
case Console:
|
||||
length := depth + 1
|
||||
if length >= 3 {
|
||||
length = 3
|
||||
}
|
||||
cref := ConsoleReference{}
|
||||
tableName := fmt.Sprintf("%s %s", strings.Repeat("#", length), paramKey)
|
||||
console = append([]ConsoleReference{cref.prepareConsoleParameter(tableName, params, types.CUECategory)}, console...)
|
||||
}
|
||||
return doc, console, nil
|
||||
}
|
||||
|
||||
// getCUEPrintableDefaultValue converts the value in `interface{}` type to be printable
|
||||
func (ref *ParseReference) getCUEPrintableDefaultValue(v interface{}) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
switch value := v.(type) {
|
||||
case Int64Type:
|
||||
return strconv.FormatInt(value, 10)
|
||||
case StringType:
|
||||
if v == "" {
|
||||
return "empty"
|
||||
}
|
||||
return value
|
||||
case BoolType:
|
||||
return strconv.FormatBool(value)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ref *ParseReference) getJSONPrintableDefaultValue(dataType string, value interface{}) string {
|
||||
if value != nil {
|
||||
return strings.TrimSpace(fmt.Sprintf("%v", value))
|
||||
}
|
||||
defaultValueMap := map[string]string{
|
||||
"number": "0",
|
||||
"boolean": "false",
|
||||
"string": "\"\"",
|
||||
"object": "{}",
|
||||
"array": "[]",
|
||||
}
|
||||
return defaultValueMap[dataType]
|
||||
}
|
||||
|
||||
// CommonReference contains parameters info of HelmCategory and KubuCategory type capability at present
|
||||
type CommonReference struct {
|
||||
Name string
|
||||
Parameters []ReferenceParameter
|
||||
Depth int
|
||||
}
|
||||
|
||||
// CommonSchema is a struct contains *openapi3.Schema style parameter
|
||||
type CommonSchema struct {
|
||||
Name string
|
||||
Schemas *openapi3.Schema
|
||||
}
|
||||
|
||||
// GenerateHelmAndKubeProperties get all properties of a Helm/Kube Category type capability
|
||||
func (ref *ParseReference) GenerateHelmAndKubeProperties(ctx context.Context, capability *types.Capability) ([]CommonReference, []ConsoleReference, error) {
|
||||
cmName := fmt.Sprintf("%s%s", types.CapabilityConfigMapNamePrefix, capability.Name)
|
||||
switch capability.Type {
|
||||
case types.TypeComponentDefinition:
|
||||
cmName = fmt.Sprintf("component-%s", cmName)
|
||||
case types.TypeTrait:
|
||||
cmName = fmt.Sprintf("trait-%s", cmName)
|
||||
default:
|
||||
}
|
||||
var cm v1.ConfigMap
|
||||
commonRefs = make([]CommonReference, 0)
|
||||
if err := ref.Client.Get(ctx, client.ObjectKey{Namespace: capability.Namespace, Name: cmName}, &cm); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
data, ok := cm.Data[types.OpenapiV3JSONSchema]
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("configMap doesn't have openapi-v3-json-schema data")
|
||||
}
|
||||
parameterJSON := fmt.Sprintf(BaseOpenAPIV3Template, data)
|
||||
swagger, err := openapi3.NewLoader().LoadFromData(json.RawMessage(parameterJSON))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
parameters := swagger.Components.Schemas[model.ParameterFieldName].Value
|
||||
WalkParameterSchema(parameters, Specification, 0)
|
||||
|
||||
var consoleRefs []ConsoleReference
|
||||
for _, item := range commonRefs {
|
||||
consoleRefs = append(consoleRefs, ref.prepareConsoleParameter(item.Name, item.Parameters, types.HelmCategory))
|
||||
}
|
||||
return commonRefs, consoleRefs, err
|
||||
}
|
||||
|
||||
// GenerateTerraformCapabilityProperties generates Capability properties for Terraform ComponentDefinition
|
||||
func (ref *ParseReference) parseTerraformCapabilityParameters(capability types.Capability) ([]ReferenceParameterTable, []ReferenceParameterTable, error) {
|
||||
var (
|
||||
tables []ReferenceParameterTable
|
||||
refParameterList []ReferenceParameter
|
||||
writeConnectionSecretToRefReferenceParameter ReferenceParameter
|
||||
configuration string
|
||||
err error
|
||||
outputsList []ReferenceParameter
|
||||
outputsTables []ReferenceParameterTable
|
||||
outputsTableName string
|
||||
)
|
||||
outputsTableName = fmt.Sprintf("%s %s\n\n%s", strings.Repeat("#", 3), ref.I18N.Get("Outputs"), ref.I18N.Get("WriteConnectionSecretToRefIntroduction"))
|
||||
|
||||
writeConnectionSecretToRefReferenceParameter.Name = terraform.TerraformWriteConnectionSecretToRefName
|
||||
writeConnectionSecretToRefReferenceParameter.PrintableType = terraform.TerraformWriteConnectionSecretToRefType
|
||||
writeConnectionSecretToRefReferenceParameter.Required = false
|
||||
writeConnectionSecretToRefReferenceParameter.Usage = terraform.TerraformWriteConnectionSecretToRefDescription
|
||||
|
||||
if capability.ConfigurationType == "remote" {
|
||||
configuration, err = utils.GetTerraformConfigurationFromRemote(capability.Name, capability.TerraformConfiguration, capability.Path)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to retrieve Terraform configuration from %s: %w", capability.Name, err)
|
||||
}
|
||||
} else {
|
||||
configuration = capability.TerraformConfiguration
|
||||
}
|
||||
|
||||
variables, outputs, err := common.ParseTerraformVariables(configuration)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to generate capability properties")
|
||||
}
|
||||
for _, v := range variables {
|
||||
var refParam ReferenceParameter
|
||||
refParam.Name = v.Name
|
||||
refParam.PrintableType = strings.ReplaceAll(v.Type, "\n", `\n`)
|
||||
refParam.Usage = strings.ReplaceAll(v.Description, "\n", `\n`)
|
||||
refParam.Required = v.Required
|
||||
refParameterList = append(refParameterList, refParam)
|
||||
}
|
||||
refParameterList = append(refParameterList, writeConnectionSecretToRefReferenceParameter)
|
||||
sort.SliceStable(refParameterList, func(i, j int) bool {
|
||||
return refParameterList[i].Name < refParameterList[j].Name
|
||||
})
|
||||
|
||||
tables = append(tables, ReferenceParameterTable{
|
||||
Name: "",
|
||||
Parameters: refParameterList,
|
||||
})
|
||||
|
||||
var (
|
||||
writeSecretRefNameParam ReferenceParameter
|
||||
writeSecretRefNameSpaceParam ReferenceParameter
|
||||
)
|
||||
|
||||
// prepare `## writeConnectionSecretToRef`
|
||||
writeSecretRefNameParam.Name = "name"
|
||||
writeSecretRefNameParam.PrintableType = "string"
|
||||
writeSecretRefNameParam.Required = true
|
||||
writeSecretRefNameParam.Usage = terraform.TerraformSecretNameDescription
|
||||
|
||||
writeSecretRefNameSpaceParam.Name = "namespace"
|
||||
writeSecretRefNameSpaceParam.PrintableType = "string"
|
||||
writeSecretRefNameSpaceParam.Required = false
|
||||
writeSecretRefNameSpaceParam.Usage = terraform.TerraformSecretNamespaceDescription
|
||||
|
||||
writeSecretRefParameterList := []ReferenceParameter{writeSecretRefNameParam, writeSecretRefNameSpaceParam}
|
||||
writeSecretTableName := fmt.Sprintf("%s %s", strings.Repeat("#", 4), terraform.TerraformWriteConnectionSecretToRefName)
|
||||
|
||||
sort.SliceStable(writeSecretRefParameterList, func(i, j int) bool {
|
||||
return writeSecretRefParameterList[i].Name < writeSecretRefParameterList[j].Name
|
||||
})
|
||||
tables = append(tables, ReferenceParameterTable{
|
||||
Name: writeSecretTableName,
|
||||
Parameters: writeSecretRefParameterList,
|
||||
})
|
||||
|
||||
// outputs
|
||||
for _, v := range outputs {
|
||||
var refParam ReferenceParameter
|
||||
refParam.Name = v.Name
|
||||
refParam.Usage = v.Description
|
||||
outputsList = append(outputsList, refParam)
|
||||
}
|
||||
|
||||
sort.SliceStable(outputsList, func(i, j int) bool {
|
||||
return outputsList[i].Name < outputsList[j].Name
|
||||
})
|
||||
outputsTables = append(outputsTables, ReferenceParameterTable{
|
||||
Name: outputsTableName,
|
||||
Parameters: outputsList,
|
||||
})
|
||||
return tables, outputsTables, nil
|
||||
}
|
||||
|
||||
// ParseLocalFile parse the local file and get name, configuration from local ComponentDefinition file
|
||||
func ParseLocalFile(localFilePath string, c common.Args) (*types.Capability, error) {
|
||||
data, err := pkgUtils.ReadRemoteOrLocalPath(localFilePath, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read local file or url")
|
||||
}
|
||||
|
||||
if strings.HasSuffix(localFilePath, "yaml") {
|
||||
jsonData, err := yaml.YAMLToJSON(data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert yaml data into k8s valid json format")
|
||||
}
|
||||
var localDefinition v1beta1.ComponentDefinition
|
||||
if err = json.Unmarshal(jsonData, &localDefinition); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal data into componentDefinition")
|
||||
}
|
||||
desc := localDefinition.ObjectMeta.Annotations["definition.oam.dev/description"]
|
||||
lcap := &types.Capability{
|
||||
Name: localDefinition.ObjectMeta.Name,
|
||||
Description: desc,
|
||||
TerraformConfiguration: localDefinition.Spec.Schematic.Terraform.Configuration,
|
||||
ConfigurationType: localDefinition.Spec.Schematic.Terraform.Type,
|
||||
Path: localDefinition.Spec.Schematic.Terraform.Path,
|
||||
}
|
||||
lcap.Type = types.TypeComponentDefinition
|
||||
lcap.Category = types.TerraformCategory
|
||||
return lcap, nil
|
||||
}
|
||||
|
||||
// local definition for general definition in CUE format
|
||||
def := pkgdef.Definition{Unstructured: unstructured.Unstructured{}}
|
||||
config, err := c.GetConfig()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get kubeconfig")
|
||||
}
|
||||
|
||||
if err = def.FromCUEString(string(data), config); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse CUE for definition")
|
||||
}
|
||||
|
||||
lcap, err := ParseCapabilityFromUnstructured(nil, def.Unstructured)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to parse definition to capability")
|
||||
}
|
||||
return &lcap, nil
|
||||
}
|
||||
|
||||
// WalkParameterSchema will extract properties from *openapi3.Schema
|
||||
func WalkParameterSchema(parameters *openapi3.Schema, name string, depth int) {
|
||||
if parameters == nil {
|
||||
return
|
||||
}
|
||||
var schemas []CommonSchema
|
||||
var commonParameters []ReferenceParameter
|
||||
for k, v := range parameters.Properties {
|
||||
p := ReferenceParameter{
|
||||
Parameter: types.Parameter{
|
||||
Name: k,
|
||||
Default: v.Value.Default,
|
||||
Usage: v.Value.Description,
|
||||
JSONType: v.Value.Type,
|
||||
},
|
||||
PrintableType: v.Value.Type,
|
||||
}
|
||||
required := false
|
||||
for _, requiredType := range parameters.Required {
|
||||
if k == requiredType {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
p.Required = required
|
||||
if v.Value.Type == "object" {
|
||||
if v.Value.Properties != nil {
|
||||
schemas = append(schemas, CommonSchema{
|
||||
Name: k,
|
||||
Schemas: v.Value,
|
||||
})
|
||||
}
|
||||
p.PrintableType = fmt.Sprintf("[%s](#%s)", k, k)
|
||||
}
|
||||
commonParameters = append(commonParameters, p)
|
||||
}
|
||||
|
||||
commonRefs = append(commonRefs, CommonReference{
|
||||
Name: fmt.Sprintf("%s %s", strings.Repeat("#", depth+1), name),
|
||||
Parameters: commonParameters,
|
||||
Depth: depth + 1,
|
||||
})
|
||||
|
||||
for _, schema := range schemas {
|
||||
WalkParameterSchema(schema.Schemas, schema.Name, depth+1)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -27,14 +26,13 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
var RefTestDir = filepath.Join(TestDir, "ref")
|
||||
@@ -46,124 +44,9 @@ func TestCreateRefTestDir(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMarkdown(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ref := &MarkdownReference{}
|
||||
|
||||
refZh := &MarkdownReference{}
|
||||
refZh.I18N = Zh
|
||||
|
||||
workloadName := "workload1"
|
||||
traitName := "trait1"
|
||||
scopeName := "scope1"
|
||||
workloadName2 := "workload2"
|
||||
|
||||
workloadCueTemplate := `
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
}
|
||||
`
|
||||
traitCueTemplate := `
|
||||
parameter: {
|
||||
replicas: int
|
||||
}
|
||||
`
|
||||
|
||||
configuration := `
|
||||
resource "alicloud_oss_bucket" "bucket-acl" {
|
||||
bucket = var.bucket
|
||||
acl = var.acl
|
||||
}
|
||||
|
||||
output "BUCKET_NAME" {
|
||||
value = "${alicloud_oss_bucket.bucket-acl.bucket}.${alicloud_oss_bucket.bucket-acl.extranet_endpoint}"
|
||||
}
|
||||
|
||||
variable "bucket" {
|
||||
description = "OSS bucket name"
|
||||
default = "vela-website"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "acl" {
|
||||
description = "OSS bucket ACL, supported 'private', 'public-read', 'public-read-write'"
|
||||
default = "private"
|
||||
type = string
|
||||
}
|
||||
`
|
||||
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
ref *MarkdownReference
|
||||
capabilities []types.Capability
|
||||
want error
|
||||
}{
|
||||
"WorkloadTypeAndTraitCapability": {
|
||||
reason: "valid capabilities",
|
||||
ref: ref,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: workloadName,
|
||||
Type: types.TypeWorkload,
|
||||
CueTemplate: workloadCueTemplate,
|
||||
Category: types.CUECategory,
|
||||
},
|
||||
{
|
||||
Name: traitName,
|
||||
Type: types.TypeTrait,
|
||||
CueTemplate: traitCueTemplate,
|
||||
Category: types.CUECategory,
|
||||
},
|
||||
{
|
||||
Name: workloadName2,
|
||||
TerraformConfiguration: configuration,
|
||||
Type: types.TypeWorkload,
|
||||
Category: types.TerraformCategory,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
"ScopeTypeCapability": {
|
||||
reason: "invalid capabilities",
|
||||
ref: ref,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: scopeName,
|
||||
Type: types.TypeScope,
|
||||
},
|
||||
},
|
||||
want: fmt.Errorf("the type of the capability is not right"),
|
||||
},
|
||||
"TerraformCapabilityInChinese": {
|
||||
reason: "terraform capability",
|
||||
ref: refZh,
|
||||
capabilities: []types.Capability{
|
||||
{
|
||||
Name: workloadName2,
|
||||
TerraformConfiguration: configuration,
|
||||
Type: types.TypeWorkload,
|
||||
Category: types.TerraformCategory,
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := tc.ref.CreateMarkdown(ctx, tc.capabilities, RefTestDir, ReferenceSourcePath, nil)
|
||||
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nCreateMakrdown(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPrepareParameterTable(t *testing.T) {
|
||||
ref := MarkdownReference{}
|
||||
ref.I18N = &En
|
||||
tableName := "hello"
|
||||
parameterList := []ReferenceParameter{
|
||||
{
|
||||
@@ -173,7 +56,7 @@ func TestPrepareParameterTable(t *testing.T) {
|
||||
parameterName := "cpu"
|
||||
parameterList[0].Name = parameterName
|
||||
parameterList[0].Required = true
|
||||
refContent := ref.prepareParameter(tableName, parameterList, types.CUECategory)
|
||||
refContent := ref.getParameterString(tableName, parameterList, types.CUECategory)
|
||||
assert.Contains(t, refContent, parameterName)
|
||||
assert.Contains(t, refContent, "cpu")
|
||||
}
|
||||
@@ -213,7 +96,7 @@ func TestWalkParameterSchema(t *testing.T) {
|
||||
"type": "object"
|
||||
}`,
|
||||
ExpectRefs: map[string]map[string]ReferenceParameter{
|
||||
"# Properties": {
|
||||
"# Specification": {
|
||||
"cmd": ReferenceParameter{
|
||||
Parameter: types.Parameter{
|
||||
Name: "cmd",
|
||||
@@ -258,7 +141,7 @@ func TestWalkParameterSchema(t *testing.T) {
|
||||
"type": "object"
|
||||
}`,
|
||||
ExpectRefs: map[string]map[string]ReferenceParameter{
|
||||
"# Properties": {
|
||||
"# Specification": {
|
||||
"obj": ReferenceParameter{
|
||||
Parameter: types.Parameter{
|
||||
Name: "obj",
|
||||
@@ -321,7 +204,7 @@ func TestWalkParameterSchema(t *testing.T) {
|
||||
"type": "object"
|
||||
}`,
|
||||
ExpectRefs: map[string]map[string]ReferenceParameter{
|
||||
"# Properties": {
|
||||
"# Specification": {
|
||||
"obj": ReferenceParameter{
|
||||
Parameter: types.Parameter{
|
||||
Name: "obj",
|
||||
@@ -367,7 +250,7 @@ func TestWalkParameterSchema(t *testing.T) {
|
||||
swagger, err := openapi3.NewLoader().LoadFromData(json.RawMessage(parameterJSON))
|
||||
assert.Equal(t, nil, err)
|
||||
parameters := swagger.Components.Schemas["parameter"].Value
|
||||
WalkParameterSchema(parameters, "Properties", 0)
|
||||
WalkParameterSchema(parameters, Specification, 0)
|
||||
refs := make(map[string]map[string]ReferenceParameter)
|
||||
for _, items := range commonRefs {
|
||||
refs[items.Name] = make(map[string]ReferenceParameter)
|
||||
@@ -423,7 +306,7 @@ variable "acl" {
|
||||
},
|
||||
want: want{
|
||||
errMsg: "",
|
||||
tableName1: "### Properties",
|
||||
tableName1: "",
|
||||
tableName2: "#### writeConnectionSecretToRef",
|
||||
},
|
||||
},
|
||||
@@ -437,7 +320,7 @@ variable "acl" {
|
||||
},
|
||||
want: want{
|
||||
errMsg: "",
|
||||
tableName1: "### Properties",
|
||||
tableName1: "",
|
||||
tableName2: "#### writeConnectionSecretToRef",
|
||||
},
|
||||
},
|
||||
@@ -525,7 +408,7 @@ func TestMakeReadableTitle(t *testing.T) {
|
||||
ref := &MarkdownReference{}
|
||||
|
||||
refZh := &MarkdownReference{}
|
||||
refZh.I18N = Zh
|
||||
refZh.I18N = &Zh
|
||||
|
||||
testcases := []struct {
|
||||
args args
|
||||
@@ -652,7 +535,7 @@ func TestParseLocalFile(t *testing.T) {
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
t.Run("", func(t *testing.T) {
|
||||
lc, err := ParseLocalFile(tc.localFilePath)
|
||||
lc, err := ParseLocalFile(tc.localFilePath, common.Args{})
|
||||
if err != nil {
|
||||
t.Errorf("ParseLocalFile(...): -want: %v, got error: %s\n", tc.want, err)
|
||||
}
|
||||
@@ -701,11 +584,13 @@ parameter: {
|
||||
cueValue, _ := common.GetCUEParameterValue(cueTemplate, nil)
|
||||
defaultDepth := 0
|
||||
defaultDisplay := "console"
|
||||
displayFormat = &defaultDisplay
|
||||
ref.parseParameters(cueValue, "Properties", defaultDepth)
|
||||
assert.Equal(t, 1, len(propertyConsole))
|
||||
propertyConsole[0].TableObject.Render()
|
||||
w.Close()
|
||||
ref.DisplayFormat = defaultDisplay
|
||||
_, console, err := ref.parseParameters("", cueValue, Specification, defaultDepth, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(console))
|
||||
console[0].TableObject.Render()
|
||||
err = w.Close()
|
||||
assert.NoError(t, err)
|
||||
out, _ := ioutil.ReadAll(r)
|
||||
assert.True(t, strings.Contains(string(out), "map[string]#KeySecret"))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
24
references/plugins/testdata/testdef.cue
vendored
Normal file
24
references/plugins/testdata/testdef.cue
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"testdef": {
|
||||
type: "component"
|
||||
annotations: {
|
||||
"definition.oam.dev/example-url": "http://127.0.0.1:65501/examples/applications/create-namespace.yaml"
|
||||
}
|
||||
labels: {}
|
||||
description: "K8s-objects allow users to specify raw K8s objects in properties"
|
||||
attributes: workload: type: "autodetects.core.oam.dev"
|
||||
}
|
||||
template: {
|
||||
output: parameter.objects[0]
|
||||
|
||||
outputs: {
|
||||
for i, v in parameter.objects {
|
||||
if i > 0 {
|
||||
"objects-\(i)": v
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=A test key
|
||||
objects: [...{}]
|
||||
}
|
||||
}
|
||||
23
references/plugins/testdata/testdeftrait.cue
vendored
Normal file
23
references/plugins/testdata/testdeftrait.cue
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
testdeftrait: {
|
||||
type: "trait"
|
||||
annotations: {}
|
||||
labels: {}
|
||||
description: "Add host aliases on K8s pod for your workload which follows the pod spec in path 'spec.template'."
|
||||
attributes: {
|
||||
podDisruptive: false
|
||||
appliesToWorkloads: ["*"]
|
||||
}
|
||||
}
|
||||
template: {
|
||||
patch: {
|
||||
// +patchKey=ip
|
||||
spec: template: spec: hostAliases: parameter.hostAliases
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
}
|
||||
}
|
||||
33
references/plugins/vars.go
Normal file
33
references/plugins/vars.go
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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 plugins
|
||||
|
||||
const (
|
||||
// Markdown marks the format name of docs
|
||||
Markdown = "markdown"
|
||||
// Console marks the format name of docs
|
||||
Console = "console"
|
||||
)
|
||||
|
||||
const (
|
||||
// Specification marks the title of parameter in reference docs
|
||||
Specification = "Specification"
|
||||
// Description marks the title of description in reference docs
|
||||
Description = "Description"
|
||||
// Examples marks the title of example in reference doc
|
||||
Examples = "Examples"
|
||||
)
|
||||
Reference in New Issue
Block a user