mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Import kube package(cue) by GroupVersion (#1309)
* package upgrade * package import * Classified by groupversion * fix test cases * add test cases * check diff * lint code * fix test * add pacakge reference * VersionKind * package upgrade package import Classified by groupversion fix test cases add test cases check diff lint code fix test add pacakge reference VersionKind fix ci
This commit is contained in:
@@ -277,7 +277,7 @@ kustomize:
|
||||
ifeq (, $(shell kustomize version | grep $(KUSTOMIZE_VERSION)))
|
||||
@{ \
|
||||
set -e ;\
|
||||
echo 'installing kustomize-v$(KUSTOMIZE_VERSION)' ;\
|
||||
echo 'installing kustomize-v$(KUSTOMIZE_VERSION) into $(GOBIN)' ;\
|
||||
curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash -s $(KUSTOMIZE_VERSION) $(GOBIN);\
|
||||
echo 'Install succeed' ;\
|
||||
}
|
||||
|
||||
@@ -110,6 +110,8 @@ func TestMakeHTTPRequest(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for testName, tt := range tests {
|
||||
// deep copy it before going to goroutine
|
||||
tt := tt
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
// generate a test server so we can capture and inspect the request
|
||||
testServer := NewMock(tt.httpParameter.method, tt.httpParameter.statusCode, tt.httpParameter.body)
|
||||
|
||||
@@ -1480,8 +1480,11 @@ spec:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
import "kube/apps/v1"
|
||||
output: v1.#Deployment & {
|
||||
import (
|
||||
"k8s.io/apps/v1"
|
||||
appsv1 "kube/apps/v1"
|
||||
)
|
||||
output: v1.#Deployment & appsv1.#Deployment & {
|
||||
metadata: {
|
||||
annotations: {
|
||||
if context["config"] != _|_ {
|
||||
@@ -1539,8 +1542,8 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
kubev1 "kube/v1"
|
||||
network "kube/networking.k8s.io/v1beta1"
|
||||
kubev1 "k8s.io/core/v1"
|
||||
network "k8s.io/networking/v1beta1"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
|
||||
+166
-57
@@ -19,6 +19,7 @@ package definition
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -36,14 +37,28 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
// BuiltinPackageDomain Specify the domain of the built-in package
|
||||
BuiltinPackageDomain = "kube"
|
||||
// K8sResourcePrefix Indicates that the definition comes from kubernetes
|
||||
K8sResourcePrefix = "io_k8s_api_"
|
||||
)
|
||||
|
||||
// PackageDiscover defines the inner CUE packages loaded from K8s cluster
|
||||
type PackageDiscover struct {
|
||||
velaBuiltinPackages []*build.Instance
|
||||
pkgKinds map[string][]string
|
||||
pkgKinds map[string][]VersionKind
|
||||
mutex sync.RWMutex
|
||||
client *rest.RESTClient
|
||||
}
|
||||
|
||||
// VersionKind contains the resource metadata and reference name
|
||||
type VersionKind struct {
|
||||
DefinitionName string
|
||||
APIVersion string
|
||||
Kind string
|
||||
}
|
||||
|
||||
// NewPackageDiscover will create a PackageDiscover client with the K8s config file.
|
||||
func NewPackageDiscover(config *rest.Config) (*PackageDiscover, error) {
|
||||
client, err := getClusterOpenAPIClient(config)
|
||||
@@ -52,7 +67,7 @@ func NewPackageDiscover(config *rest.Config) (*PackageDiscover, error) {
|
||||
}
|
||||
pd := &PackageDiscover{
|
||||
client: client,
|
||||
pkgKinds: make(map[string][]string),
|
||||
pkgKinds: make(map[string][]VersionKind),
|
||||
}
|
||||
if err = pd.RefreshKubePackagesFromCluster(); err != nil {
|
||||
return nil, err
|
||||
@@ -67,6 +82,13 @@ func (pd *PackageDiscover) ImportBuiltinPackagesFor(bi *build.Instance) {
|
||||
bi.Imports = append(bi.Imports, pd.velaBuiltinPackages...)
|
||||
}
|
||||
|
||||
// ListPackageKinds list packages and their kinds
|
||||
func (pd *PackageDiscover) ListPackageKinds() map[string][]VersionKind {
|
||||
pd.mutex.RLock()
|
||||
defer pd.mutex.RUnlock()
|
||||
return pd.pkgKinds
|
||||
}
|
||||
|
||||
// RefreshKubePackagesFromCluster will use K8s client to load/refresh all K8s open API as a reference kube package using in template
|
||||
func (pd *PackageDiscover) RefreshKubePackagesFromCluster() error {
|
||||
body, err := pd.client.Get().AbsPath("/openapi/v2").Do(context.Background()).Raw()
|
||||
@@ -78,13 +100,14 @@ func (pd *PackageDiscover) RefreshKubePackagesFromCluster() error {
|
||||
|
||||
// Exist checks if the GVK exists in the built-in packages
|
||||
func (pd *PackageDiscover) Exist(gvk metav1.GroupVersionKind) bool {
|
||||
dgvk := convert2DGVK(gvk)
|
||||
// package name equals to importPath
|
||||
importPath := genPackageName(gvk.Group, gvk.Version)
|
||||
importPath := genStandardPkgName(dgvk)
|
||||
pd.mutex.RLock()
|
||||
defer pd.mutex.RUnlock()
|
||||
pkgKinds := pd.pkgKinds[importPath]
|
||||
for _, k := range pkgKinds {
|
||||
if k == gvk.Kind {
|
||||
for _, v := range pkgKinds {
|
||||
if v.Kind == dgvk.Kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -92,7 +115,7 @@ func (pd *PackageDiscover) Exist(gvk metav1.GroupVersionKind) bool {
|
||||
}
|
||||
|
||||
// mount will mount the new parsed package into PackageDiscover built-in packages
|
||||
func (pd *PackageDiscover) mount(pkg *pkgInstance, pkgKinds []string) {
|
||||
func (pd *PackageDiscover) mount(pkg *pkgInstance, pkgKinds []VersionKind) {
|
||||
pd.mutex.Lock()
|
||||
defer pd.mutex.Unlock()
|
||||
for i, p := range pd.velaBuiltinPackages {
|
||||
@@ -111,7 +134,7 @@ func (pd *PackageDiscover) addKubeCUEPackagesFromCluster(apiSchema string) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kinds := map[string]metav1.GroupVersionKind{}
|
||||
dgvkMapper := make(map[string]domainGroupVersionKind)
|
||||
pathValue := oaInst.Value().Lookup("paths")
|
||||
if pathValue.Exists() {
|
||||
if st, err := pathValue.Struct(); err == nil {
|
||||
@@ -120,8 +143,8 @@ func (pd *PackageDiscover) addKubeCUEPackagesFromCluster(apiSchema string) error
|
||||
gvk := iter.Value().Lookup("post",
|
||||
"x-kubernetes-group-version-kind")
|
||||
if gvk.Exists() {
|
||||
if v, err := getGVK(gvk); err == nil {
|
||||
kinds["#"+v.Kind] = v
|
||||
if v, err := getDGVK(gvk); err == nil {
|
||||
dgvkMapper[v.reverseString()] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,55 +152,75 @@ func (pd *PackageDiscover) addKubeCUEPackagesFromCluster(apiSchema string) error
|
||||
}
|
||||
oaFile, err := jsonschema.Extract(oaInst, &jsonschema.Config{
|
||||
Root: "#/definitions",
|
||||
Map: openAPIMapping,
|
||||
Map: openAPIMapping(dgvkMapper),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubePkg := newPackage("kube")
|
||||
kubePkg.processOpenAPIFile(oaFile)
|
||||
if err := kubePkg.AddSyntax(oaFile); err != nil {
|
||||
return err
|
||||
}
|
||||
packages := make(map[string]*pkgInstance)
|
||||
groupKinds := make(map[string][]string)
|
||||
groupKinds := make(map[string][]VersionKind)
|
||||
|
||||
for k, v := range kinds {
|
||||
apiVersion := v.Version
|
||||
if v.Group != "" {
|
||||
apiVersion = v.Group + "/" + apiVersion
|
||||
}
|
||||
def := fmt.Sprintf(`%s: {
|
||||
for k := range dgvkMapper {
|
||||
v := dgvkMapper[k]
|
||||
apiVersion := v.APIVersion
|
||||
def := fmt.Sprintf(`
|
||||
import "kube"
|
||||
|
||||
#%s: kube.%s & {
|
||||
kind: "%s"
|
||||
apiVersion: "%s",
|
||||
}`, k, v.Kind, apiVersion)
|
||||
pkgName := genPackageName(v.Group, v.Version)
|
||||
pkg, ok := packages[pkgName]
|
||||
if !ok {
|
||||
pkg = newPackage(pkgName)
|
||||
}`, v.Kind, k, v.Kind, apiVersion)
|
||||
|
||||
pkgBuild := func(pkgName string) error {
|
||||
pkg, ok := packages[pkgName]
|
||||
if !ok {
|
||||
pkg = newPackage(pkgName)
|
||||
pkg.Imports = []*build.Instance{kubePkg.Instance}
|
||||
}
|
||||
|
||||
mykinds := groupKinds[pkgName]
|
||||
mykinds = append(mykinds, VersionKind{
|
||||
APIVersion: v.APIVersion,
|
||||
Kind: v.Kind,
|
||||
DefinitionName: "#" + v.Kind,
|
||||
})
|
||||
|
||||
if err := pkg.AddFile(v.reverseString(), def); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packages[pkgName] = pkg
|
||||
groupKinds[pkgName] = mykinds
|
||||
return nil
|
||||
}
|
||||
|
||||
mykinds := groupKinds[pkgName]
|
||||
mykinds = append(mykinds, v.Kind)
|
||||
|
||||
if err := pkg.AddFile(k, def); err != nil {
|
||||
if err := pkgBuild(genStandardPkgName(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pkgBuild(genOpenPkgName(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
packages[pkgName] = pkg
|
||||
groupKinds[pkgName] = mykinds
|
||||
}
|
||||
for name, pkg := range packages {
|
||||
pkg.processOpenAPIFile(oaFile)
|
||||
if err = pkg.AddSyntax(oaFile); err != nil {
|
||||
return err
|
||||
}
|
||||
pd.mount(pkg, groupKinds[name])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genPackageName(group, version string) string {
|
||||
res := []string{"kube"}
|
||||
if group != "" {
|
||||
res = append(res, group)
|
||||
func genOpenPkgName(v domainGroupVersionKind) string {
|
||||
return BuiltinPackageDomain + "/" + v.APIVersion
|
||||
}
|
||||
|
||||
func genStandardPkgName(v domainGroupVersionKind) string {
|
||||
res := []string{v.Group, v.Version}
|
||||
if v.Domain != "" {
|
||||
res = []string{v.Domain, v.Group, v.Version}
|
||||
}
|
||||
// version should never be empty
|
||||
res = append(res, version)
|
||||
|
||||
return strings.Join(res, "/")
|
||||
}
|
||||
|
||||
@@ -207,18 +250,56 @@ func getClusterOpenAPIClient(config *rest.Config) (*rest.RESTClient, error) {
|
||||
return rest.UnversionedRESTClientFor(©Config)
|
||||
}
|
||||
|
||||
func openAPIMapping(pos token.Pos, a []string) ([]ast.Label, error) {
|
||||
if len(a) < 2 {
|
||||
return nil, errors.New("openAPIMapping format invalid")
|
||||
func openAPIMapping(dgvkMapper map[string]domainGroupVersionKind) func(pos token.Pos, a []string) ([]ast.Label, error) {
|
||||
return func(pos token.Pos, a []string) ([]ast.Label, error) {
|
||||
if len(a) < 2 {
|
||||
return nil, errors.New("openAPIMapping format invalid")
|
||||
}
|
||||
|
||||
name := strings.ReplaceAll(a[1], ".", "_")
|
||||
|
||||
if _, ok := dgvkMapper[name]; !ok && strings.HasPrefix(name, K8sResourcePrefix) {
|
||||
trimName := strings.TrimPrefix(name, K8sResourcePrefix)
|
||||
if v, ok := dgvkMapper[trimName]; ok {
|
||||
v.Domain = "k8s.io"
|
||||
dgvkMapper[name] = v
|
||||
delete(dgvkMapper, trimName)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(a[1], ".JSONSchemaProps") && pos != token.NoPos {
|
||||
return []ast.Label{ast.NewIdent("_")}, nil
|
||||
}
|
||||
|
||||
return []ast.Label{ast.NewIdent(name)}, nil
|
||||
}
|
||||
|
||||
spl := strings.Split(a[1], ".")
|
||||
name := spl[len(spl)-1]
|
||||
}
|
||||
|
||||
if name == "JSONSchemaProps" && pos != token.NoPos {
|
||||
return []ast.Label{ast.NewIdent("_")}, nil
|
||||
type domainGroupVersionKind struct {
|
||||
Domain string
|
||||
Group string
|
||||
Version string
|
||||
Kind string
|
||||
APIVersion string
|
||||
}
|
||||
|
||||
func (dgvk domainGroupVersionKind) reverseString() string {
|
||||
var s = []string{dgvk.Kind, dgvk.Version}
|
||||
s = append(s, strings.Split(dgvk.Group, ".")...)
|
||||
domain := dgvk.Domain
|
||||
if domain == "k8s.io" {
|
||||
domain = "api.k8s.io"
|
||||
}
|
||||
return []ast.Label{ast.NewIdent("#" + name)}, nil
|
||||
|
||||
if domain != "" {
|
||||
s = append(s, strings.Split(domain, ".")...)
|
||||
}
|
||||
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
return strings.Join(s, "_")
|
||||
}
|
||||
|
||||
type pkgInstance struct {
|
||||
@@ -228,7 +309,7 @@ type pkgInstance struct {
|
||||
func newPackage(name string) *pkgInstance {
|
||||
return &pkgInstance{
|
||||
&build.Instance{
|
||||
PkgName: name,
|
||||
PkgName: filepath.Base(name),
|
||||
ImportPath: name,
|
||||
},
|
||||
}
|
||||
@@ -264,17 +345,45 @@ func (pkg *pkgInstance) processOpenAPIFile(f *ast.File) {
|
||||
}
|
||||
}
|
||||
|
||||
func getGVK(v cue.Value) (metav1.GroupVersionKind, error) {
|
||||
ret := metav1.GroupVersionKind{}
|
||||
var err error
|
||||
ret.Group, err = v.Lookup("group").String()
|
||||
func getDGVK(v cue.Value) (ret domainGroupVersionKind, err error) {
|
||||
gvk := metav1.GroupVersionKind{}
|
||||
gvk.Group, err = v.Lookup("group").String()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
return
|
||||
}
|
||||
ret.Version, err = v.Lookup("version").String()
|
||||
gvk.Version, err = v.Lookup("version").String()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
return
|
||||
}
|
||||
ret.Kind, err = v.Lookup("kind").String()
|
||||
return ret, err
|
||||
|
||||
gvk.Kind, err = v.Lookup("kind").String()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ret = convert2DGVK(gvk)
|
||||
return
|
||||
}
|
||||
|
||||
func convert2DGVK(gvk metav1.GroupVersionKind) domainGroupVersionKind {
|
||||
ret := domainGroupVersionKind{
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.Version,
|
||||
}
|
||||
if gvk.Group == "" {
|
||||
ret.Group = "core"
|
||||
ret.Domain = "k8s.io"
|
||||
} else {
|
||||
ret.APIVersion = gvk.Group + "/" + ret.APIVersion
|
||||
sv := strings.Split(gvk.Group, ".")
|
||||
// Domain must contain dot
|
||||
if len(sv) > 2 {
|
||||
ret.Domain = strings.Join(sv[1:], ".")
|
||||
ret.Group = sv[0]
|
||||
} else {
|
||||
ret.Group = gvk.Group
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -20,11 +20,12 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/build"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@@ -38,17 +39,17 @@ import (
|
||||
|
||||
var _ = Describe("Package discovery resources for definition from K8s APIServer", func() {
|
||||
|
||||
PIt("discovery built-in k8s resource", func() {
|
||||
It("discovery built-in k8s resource", func() {
|
||||
|
||||
By("test ingress in kube package")
|
||||
bi := build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
err := bi.AddFile("-", `
|
||||
import (
|
||||
network "kube/networking.k8s.io/v1beta1"
|
||||
network "k8s.io/networking/v1beta1"
|
||||
kube "kube/networking.k8s.io/v1beta1"
|
||||
)
|
||||
|
||||
output: network.#Ingress
|
||||
output: network.#Ingress & kube.#Ingress
|
||||
output: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
@@ -102,16 +103,46 @@ parameter: {
|
||||
"servicePort": int64(80),
|
||||
}}}}}}}},
|
||||
})).Should(BeEquivalentTo(""))
|
||||
By("test Invalid Import path")
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import (
|
||||
"k8s.io/networking/v1"
|
||||
kube "kube/networking.k8s.io/v1"
|
||||
)
|
||||
output: v1.#Deployment & kube.#Deployment
|
||||
output: {
|
||||
metadata: {
|
||||
"name": parameter.name
|
||||
}
|
||||
spec: template: spec: {
|
||||
containers: [{
|
||||
name:"invalid-path",
|
||||
image: parameter.image
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
name: "myapp"
|
||||
image: "nginx"
|
||||
}`)
|
||||
inst, err = r.Build(bi)
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = model.NewBase(inst.Lookup("output"))
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(err.Error()).Should(Equal("_|_ // undefined field \"#Deployment\""))
|
||||
|
||||
By("test Deployment in kube package")
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import (
|
||||
apps "kube/apps/v1"
|
||||
apps "k8s.io/apps/v1"
|
||||
kube "kube/apps/v1"
|
||||
)
|
||||
|
||||
output: apps.#Deployment
|
||||
output: apps.#Deployment & kube.#Deployment
|
||||
output: {
|
||||
metadata: {
|
||||
"name": parameter.name
|
||||
@@ -123,7 +154,6 @@ output: {
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
name: "myapp"
|
||||
image: "nginx"
|
||||
@@ -152,16 +182,17 @@ parameter: {
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import ("kube/v1")
|
||||
|
||||
output: v1.#Secret
|
||||
import (
|
||||
"k8s.io/core/v1"
|
||||
kube "kube/v1"
|
||||
)
|
||||
output: v1.#Secret & kube.#Secret
|
||||
output: {
|
||||
metadata: {
|
||||
"name": parameter.name
|
||||
}
|
||||
type:"kubevela"
|
||||
}
|
||||
|
||||
parameter: {
|
||||
name: "myapp"
|
||||
}`)
|
||||
@@ -181,16 +212,17 @@ parameter: {
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import ("kube/v1")
|
||||
|
||||
output: v1.#Service
|
||||
import (
|
||||
"k8s.io/core/v1"
|
||||
kube "kube/v1"
|
||||
)
|
||||
output: v1.#Service & kube.#Service
|
||||
output: {
|
||||
metadata: {
|
||||
"name": parameter.name
|
||||
}
|
||||
spec: type: "ClusterIP",
|
||||
}
|
||||
|
||||
parameter: {
|
||||
name: "myapp"
|
||||
}`)
|
||||
@@ -274,10 +306,12 @@ parameter: {
|
||||
}
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
pd.ImportBuiltinPackagesFor(bi)
|
||||
if err = bi.AddFile("-", `
|
||||
import ("kube/example.com/v1")
|
||||
|
||||
output: v1.#Foo
|
||||
if err := bi.AddFile("-", `
|
||||
import (
|
||||
ev1 "example.com/v1"
|
||||
kv1 "kube/example.com/v1"
|
||||
)
|
||||
output: ev1.#Foo & kv1.#Foo
|
||||
output: {
|
||||
spec: key: "test1"
|
||||
status: key: "test2"
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"cuelang.org/go/cue/build"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"cuelang.org/go/cue/token"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gotest.tools/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -37,7 +38,7 @@ func TestPackage(t *testing.T) {
|
||||
"paths...": {
|
||||
"post":{
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "test.io",
|
||||
"group": "apps.test.io",
|
||||
"kind": "Bucket",
|
||||
"version": "v1"
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func TestPackage(t *testing.T) {
|
||||
}
|
||||
},
|
||||
"definitions":{
|
||||
"Bucket":{
|
||||
"io.test.apps.v1.Bucket":{
|
||||
"properties":{
|
||||
"apiVersion": {"type": "string"}
|
||||
"kind": {"type": "string"}
|
||||
@@ -330,12 +331,85 @@ func TestPackage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
`
|
||||
mypd := &PackageDiscover{pkgKinds: make(map[string][]string)}
|
||||
mypd := &PackageDiscover{pkgKinds: make(map[string][]VersionKind)}
|
||||
mypd.addKubeCUEPackagesFromCluster(openAPISchema)
|
||||
expectPkgKinds := map[string][]VersionKind{
|
||||
"test.io/apps/v1": []VersionKind{{
|
||||
DefinitionName: "#Bucket",
|
||||
APIVersion: "apps.test.io/v1",
|
||||
Kind: "Bucket",
|
||||
}},
|
||||
"kube/apps.test.io/v1": []VersionKind{{
|
||||
DefinitionName: "#Bucket",
|
||||
APIVersion: "apps.test.io/v1",
|
||||
Kind: "Bucket",
|
||||
}},
|
||||
}
|
||||
assert.Equal(t, cmp.Diff(mypd.ListPackageKinds(), expectPkgKinds), "")
|
||||
|
||||
exceptObj := `output: close({
|
||||
kind: "Bucket"
|
||||
apiVersion: "apps.test.io/v1"
|
||||
type: "alicloud_oss_bucket"
|
||||
acl: "public-read-write" | "public-read" | *"private"
|
||||
dataRedundancyType?: "ZRS" | *"LRS"
|
||||
dataSourceRef?: {
|
||||
dsPath: string
|
||||
}
|
||||
importRef?: {
|
||||
importKey: string
|
||||
}
|
||||
output: {
|
||||
{[!~"^(bucketName|extranetEndpoint|intranetEndpoint|masterUserId)$"]: {
|
||||
outRef: string
|
||||
} | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}}
|
||||
bucketName: {
|
||||
outRef: "self.name"
|
||||
}
|
||||
extranetEndpoint: {
|
||||
outRef: "self.state.extranetEndpoint"
|
||||
}
|
||||
intranetEndpoint: {
|
||||
outRef: "self.state.intranetEndpoint"
|
||||
}
|
||||
masterUserId: {
|
||||
outRef: "self.state.masterUserId"
|
||||
}
|
||||
}
|
||||
profile: {
|
||||
baasRepo: string | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}
|
||||
cloudProduct: "AliCloudOSS"
|
||||
endpoint?: string | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}
|
||||
envType?: "testing" | "product" | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}
|
||||
provider: "alicloud"
|
||||
region: string | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}
|
||||
serviceAccount?: string | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}
|
||||
}
|
||||
storageClass?: "IA" | "Archive" | "ColdArchive" | *"Standard"
|
||||
})
|
||||
`
|
||||
bi := build.NewContext().NewInstance("", nil)
|
||||
mypd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import "kube/test.io/v1"
|
||||
import "test.io/apps/v1"
|
||||
output: v1.#Bucket
|
||||
`)
|
||||
var r cue.Runtime
|
||||
@@ -343,66 +417,19 @@ output: v1.#Bucket
|
||||
assert.NilError(t, err)
|
||||
base, err := model.NewBase(inst.Value())
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, base.String(), exceptObj)
|
||||
|
||||
exceptObj := `output: close({
|
||||
kind: "Bucket"
|
||||
apiVersion: "test.io/v1"
|
||||
type: "alicloud_oss_bucket"
|
||||
acl: "public-read-write" | "public-read" | *"private"
|
||||
dataRedundancyType?: "ZRS" | *"LRS"
|
||||
dataSourceRef?: close({
|
||||
dsPath: string
|
||||
})
|
||||
importRef?: close({
|
||||
importKey: string
|
||||
})
|
||||
output: close({
|
||||
{[!~"^(bucketName|extranetEndpoint|intranetEndpoint|masterUserId)$"]: {
|
||||
outRef: string
|
||||
} | {
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
}}
|
||||
bucketName: close({
|
||||
outRef: "self.name"
|
||||
})
|
||||
extranetEndpoint: close({
|
||||
outRef: "self.state.extranetEndpoint"
|
||||
})
|
||||
intranetEndpoint: close({
|
||||
outRef: "self.state.intranetEndpoint"
|
||||
})
|
||||
masterUserId: close({
|
||||
outRef: "self.state.masterUserId"
|
||||
})
|
||||
})
|
||||
profile: close({
|
||||
baasRepo: string | close({
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
})
|
||||
cloudProduct: "AliCloudOSS"
|
||||
endpoint?: string | close({
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
})
|
||||
envType?: "testing" | "product" | close({
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
})
|
||||
provider: "alicloud"
|
||||
region: string | close({
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
})
|
||||
serviceAccount?: string | close({
|
||||
// Example: demoVpc.vpcId
|
||||
valueRef: string
|
||||
})
|
||||
})
|
||||
storageClass?: "IA" | "Archive" | "ColdArchive" | *"Standard"
|
||||
})
|
||||
`
|
||||
bi = build.NewContext().NewInstance("", nil)
|
||||
mypd.ImportBuiltinPackagesFor(bi)
|
||||
bi.AddFile("-", `
|
||||
import "kube/apps.test.io/v1"
|
||||
output: v1.#Bucket
|
||||
`)
|
||||
|
||||
inst, err = r.Build(bi)
|
||||
assert.NilError(t, err)
|
||||
base, err = model.NewBase(inst.Value())
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, base.String(), exceptObj)
|
||||
}
|
||||
|
||||
@@ -444,20 +471,20 @@ func TestProcessFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMount(t *testing.T) {
|
||||
mypd := &PackageDiscover{pkgKinds: make(map[string][]string)}
|
||||
mypd := &PackageDiscover{pkgKinds: make(map[string][]VersionKind)}
|
||||
testPkg := newPackage("foo")
|
||||
mypd.mount(testPkg, []string{"abc"})
|
||||
mypd.mount(testPkg, []VersionKind{})
|
||||
assert.Equal(t, len(mypd.velaBuiltinPackages), 1)
|
||||
mypd.mount(testPkg, []string{"abc"})
|
||||
mypd.mount(testPkg, []VersionKind{})
|
||||
assert.Equal(t, len(mypd.velaBuiltinPackages), 1)
|
||||
assert.Equal(t, mypd.velaBuiltinPackages[0], testPkg.Instance)
|
||||
}
|
||||
|
||||
func TestGetGVK(t *testing.T) {
|
||||
func TestGetDGVK(t *testing.T) {
|
||||
srcTmpl := `
|
||||
{
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "test.io",
|
||||
"group": "apps.test.io",
|
||||
"kind": "Foo",
|
||||
"version": "v1"
|
||||
}
|
||||
@@ -466,12 +493,34 @@ func TestGetGVK(t *testing.T) {
|
||||
var r cue.Runtime
|
||||
inst, err := r.Compile("-", srcTmpl)
|
||||
assert.NilError(t, err)
|
||||
gvk, err := getGVK(inst.Value().Lookup("x-kubernetes-group-version-kind"))
|
||||
gvk, err := getDGVK(inst.Value().Lookup("x-kubernetes-group-version-kind"))
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, gvk, metav1.GroupVersionKind{
|
||||
Group: "test.io",
|
||||
Version: "v1",
|
||||
Kind: "Foo",
|
||||
assert.Equal(t, gvk, domainGroupVersionKind{
|
||||
Domain: "test.io",
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Foo",
|
||||
APIVersion: "apps.test.io/v1",
|
||||
})
|
||||
|
||||
srcTmpl = `
|
||||
{
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "test.io",
|
||||
"kind": "Foo",
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
`
|
||||
inst, err = r.Compile("-", srcTmpl)
|
||||
assert.NilError(t, err)
|
||||
gvk, err = getDGVK(inst.Value().Lookup("x-kubernetes-group-version-kind"))
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, gvk, domainGroupVersionKind{
|
||||
Group: "test.io",
|
||||
Version: "v1",
|
||||
Kind: "Foo",
|
||||
APIVersion: "test.io/v1",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -485,7 +534,7 @@ func TestOpenAPIMapping(t *testing.T) {
|
||||
{
|
||||
input: []string{"definitions", "io.k8s.api.discovery.v1beta1.Endpoint"},
|
||||
pos: token.NoPos,
|
||||
result: "[#Endpoint]",
|
||||
result: "[io_k8s_api_discovery_v1beta1_Endpoint]",
|
||||
},
|
||||
{
|
||||
input: []string{"definitions", "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps"},
|
||||
@@ -495,7 +544,7 @@ func TestOpenAPIMapping(t *testing.T) {
|
||||
{
|
||||
input: []string{"definitions", "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps"},
|
||||
pos: token.NoPos,
|
||||
result: "[#JSONSchemaProps]",
|
||||
result: "[io_k8s_apiextensions-apiserver_pkg_apis_apiextensions_v1_JSONSchemaProps]",
|
||||
},
|
||||
{
|
||||
input: []string{"definitions"},
|
||||
@@ -504,8 +553,9 @@ func TestOpenAPIMapping(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
emptyMapper := make(map[string]domainGroupVersionKind)
|
||||
for _, tCase := range testCases {
|
||||
labels, err := openAPIMapping(tCase.pos, tCase.input)
|
||||
labels, err := openAPIMapping(emptyMapper)(tCase.pos, tCase.input)
|
||||
if tCase.errMsg != "" {
|
||||
assert.Error(t, err, tCase.errMsg)
|
||||
continue
|
||||
@@ -515,3 +565,70 @@ func TestOpenAPIMapping(t *testing.T) {
|
||||
assert.Equal(t, tCase.result, fmt.Sprint(labels))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePkgName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
dgvk domainGroupVersionKind
|
||||
sdPkgName string
|
||||
openPkgName string
|
||||
}{
|
||||
{
|
||||
dgvk: domainGroupVersionKind{
|
||||
Domain: "k8s.io",
|
||||
Group: "networking",
|
||||
Version: "v1",
|
||||
Kind: "Ingress",
|
||||
},
|
||||
sdPkgName: "k8s.io/networking/v1",
|
||||
openPkgName: "kube/networking.k8s.io",
|
||||
},
|
||||
{
|
||||
dgvk: domainGroupVersionKind{
|
||||
Group: "example.com",
|
||||
Version: "v1",
|
||||
Kind: "Sls",
|
||||
},
|
||||
sdPkgName: "example.com/v1",
|
||||
openPkgName: "kube/example.com/v1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tCase := range testCases {
|
||||
assert.Equal(t, genStandardPkgName(tCase.dgvk), tCase.sdPkgName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
gvr metav1.GroupVersionKind
|
||||
reverseString string
|
||||
}{
|
||||
{
|
||||
gvr: metav1.GroupVersionKind{
|
||||
Group: "networking.k8s.io",
|
||||
Version: "v1",
|
||||
Kind: "NetworkPolicy",
|
||||
},
|
||||
reverseString: "io_k8s_api_networking_v1_NetworkPolicy",
|
||||
},
|
||||
{
|
||||
gvr: metav1.GroupVersionKind{
|
||||
Group: "example.com",
|
||||
Version: "v1",
|
||||
Kind: "Sls",
|
||||
},
|
||||
reverseString: "com_example_v1_Sls",
|
||||
},
|
||||
{
|
||||
gvr: metav1.GroupVersionKind{
|
||||
Version: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
reverseString: "io_k8s_api_core_v1_Pod",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tCase := range testCases {
|
||||
assert.Equal(t, convert2DGVK(tCase.gvr).reverseString(), tCase.reverseString)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user