Files
kubevela/references/cli/registry.go
Somefive 7103f8ff52 Feat: merge master into apiserver (#2660)
* Feat(rollout): fill rolloutBatches if empty when scale up/down (#2569)

* Feat: fill rolloutBatches if empty

* Fix: fix unit-test

* Test: add more test

Fix: lint

Fix: fix lint

* Update release.yml (#2537)

* Feat: add registry, merge registry and cap center (#2528)

* Feat: add registry command

* Refactor: comp/trait command combine with registry

* Feat: refactor `vela comp/trait`

* Fix: import

* Fix: fix if type is autodetects.core.oam.dev

* Fix: fix list from url

* Fix: test

* Feat: add test

* Fix: remove dup test

* Fix: test

* Fix: test

* Fix: fix label filter

* Fix: reviewable

* Fix test

* fix personal repo in test

* Fix test

* Fix test

* add some boundary check

* reviewable

* Fix: fix nocalhost trait (#2577)

* fix incorrect addon status (#2576)

* Fix(cli): client-side throttling in vela CLI (#2581)

* fix cli throttling

* fix import

* set to a lower value

* remove addon with no defs (#2574)

* Feat: vela logs support multicluster (#2593)

* Feat: add basic multiple cluster logs

* fix context

* Fix select style

* Fix select style

* remove useless env

* fix naming

* Feat: vela cluster support use ocm to join/list/detach cluster (#2599)

* Feat: add render component and apply component remaining (#2587)

* Feat: add render component and apply component remaining

* fix ut

* fix e2e

* allow import package in custom status cue template (#2585)

Co-authored-by: chwetion <chwetion@foxmail.com>

* Fix: abnormal aux name (#2612)

* Feat: store workflow step def properties in cm (#2592)

* Fix: fix notification def

* Feat: store workflow step def properties in cm

* fix ci

* fix data race

* Fix: change Initializer to Application for addon Observability (#2615)

In this doc, updated the Observability implementation from initializer
to Application. I also store definitions as it's not well stored in
vela-templates/addons/observability

* Fix: fix backport param (#2611)

* Fix: add owner reference in workflow context cm (#2573)

* Fix: add owner reference in workflow context cm

* fix ci

* delete useless test case

* Fix: op.delete bugs (#2622)

* Fix: op.delete some bugs

* Fix: app status update error

Fix: make reviewable

* Fix: show reconcile error log (#2626)

* Feat: add reconcile timeout configuration for vela-core (#2630)

* Fix: patch status retry while conflict happens (#2629)

* Fix: allow definition schema cm can be same name in different definition type (#2618)

* Fix: fix definition schema cm name

* fix ut

* fix ut

* fix show

* add switch default case

* Feat: remove envbinding policy into workflow (#2556)

Fix: add more test

* Feat: add vela prob to test cluster (#2635)

* Fix: upgrade stern lib to avoid panic for vela logs (#2650)

* Fix: filter loggable workload in vela logs (#2651)

* Fix: filter loggable workload in vela logs

* reviewable

* Feat: add vela exec for multi cluster (#2299)

fix

support vela exec

* Fix: health check will check for multiclusters (#2645)

* Fix: minor fix for vela cli printing (#2655)

* Fix: minor fix for vela cli printing

* add dockerfile go mod cache

* Feat: support apiserver-related multicluster features (#2625)

* Feat: remove envbinding policy into workflow

Feat: add support for env change (env gc)

Fix: fix rollout timeout setting bug

* Feat: support disable trait and env without workflow

* Fix: add hint for replaced value

Co-authored-by: wyike <wangyike_wyk@163.com>
Co-authored-by: basefas <basefas@hotmail.com>
Co-authored-by: qiaozp <47812250+chivalryq@users.noreply.github.com>
Co-authored-by: Tianxin Dong <dongtianxin.tx@alibaba-inc.com>
Co-authored-by: yangsoon <yangsoonlx@gmail.com>
Co-authored-by: Chwetion <137953601@qq.com>
Co-authored-by: chwetion <chwetion@foxmail.com>
Co-authored-by: Jian.Li <74582607+leejanee@users.noreply.github.com>
Co-authored-by: Zheng Xi Zhou <zzxwill@gmail.com>
Co-authored-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2021-11-09 13:06:55 +08:00

774 lines
20 KiB
Go

/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import (
"context"
"encoding/base64"
"encoding/xml"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"github.com/google/go-github/v32/github"
"golang.org/x/oauth2"
"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"
apis "github.com/oam-dev/kubevela/references/apis"
"github.com/oam-dev/kubevela/references/plugins"
"github.com/pkg/errors"
"github.com/spf13/cobra"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
// NewRegistryCommand Manage Capability Center
func NewRegistryCommand(ioStream cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "registry <command>",
Short: "Manage Registry",
Long: "Manage Registry with config, remove, list",
}
cmd.AddCommand(
NewRegistryConfigCommand(ioStream),
NewRegistryListCommand(ioStream),
NewRegistryRemoveCommand(ioStream),
)
return cmd
}
// NewRegistryListCommand List all registry
func NewRegistryListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "ls",
Short: "List all registry",
Long: "List all configured registry",
Example: `vela registry ls`,
RunE: func(cmd *cobra.Command, args []string) error {
return listCapRegistrys(ioStreams)
},
}
return cmd
}
// NewRegistryConfigCommand Configure (add if not exist) a registry, default is local (built-in capabilities)
func NewRegistryConfigCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "config <registryName> <centerURL>",
Short: "Configure (add if not exist) a registry, default is local (built-in capabilities)",
Long: "Configure (add if not exist) a registry, default is local (built-in capabilities)",
Example: `vela registry config my-registry https://github.com/oam-dev/catalog/tree/master/registry`,
RunE: func(cmd *cobra.Command, args []string) error {
argsLength := len(args)
if argsLength < 2 {
return errors.New("please set registry with <centerName> and <centerURL>")
}
capName := args[0]
capURL := args[1]
token := cmd.Flag("token").Value.String()
if err := addRegistry(capName, capURL, token); err != nil {
return err
}
ioStreams.Infof("Successfully configured registry %s\n", capName)
return nil
},
}
cmd.PersistentFlags().StringP("token", "t", "", "Github Repo token")
return cmd
}
// NewRegistryRemoveCommand Remove specified registry
func NewRegistryRemoveCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Aliases: []string{"rm"},
Use: "remove <centerName>",
Short: "Remove specified registry",
Long: "Remove specified registry",
Example: "vela registry remove mycenter",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("you must specify <name> for capability center you want to remove")
}
centerName := args[0]
msg, err := removeRegistry(centerName)
if err == nil {
ioStreams.Info(msg)
}
return err
},
}
return cmd
}
func listCapRegistrys(ioStreams cmdutil.IOStreams) error {
table := newUITable()
table.MaxColWidth = 80
table.AddRow("NAME", "URL")
registrys, err := ListRegistryConfig()
if err != nil {
return errors.Wrap(err, "list registry error")
}
for _, c := range registrys {
tokenShow := ""
if len(c.Token) > 0 {
tokenShow = "***"
}
table.AddRow(c.Name, c.URL, tokenShow)
}
ioStreams.Info(table.String())
return nil
}
// addRegistry will add a registry
func addRegistry(regName, regURL, regToken string) error {
regConfig := apis.RegistryConfig{
Name: regName, URL: regURL, Token: regToken,
}
repos, err := ListRegistryConfig()
if err != nil {
return err
}
var updated bool
for idx, r := range repos {
if r.Name == regConfig.Name {
repos[idx] = regConfig
updated = true
break
}
}
if !updated {
repos = append(repos, regConfig)
}
if err = StoreRepos(repos); err != nil {
return err
}
return nil
}
// removeRegistry will remove a registry from local
func removeRegistry(regName string) (string, error) {
var message string
var err error
regConfigs, err := ListRegistryConfig()
if err != nil {
return message, err
}
found := false
for idx, r := range regConfigs {
if r.Name == regName {
regConfigs = append(regConfigs[:idx], regConfigs[idx+1:]...)
found = true
break
}
}
if !found {
return fmt.Sprintf("registry %s not found", regName), nil
}
if err = StoreRepos(regConfigs); err != nil {
return message, err
}
message = fmt.Sprintf("Successfully remove registry %s", regName)
return message, err
}
// DefaultRegistry is default registry
const DefaultRegistry = "default"
// Registry define a registry used to get and list types.Capability
type Registry interface {
GetName() string
GetURL() string
GetCap(addonName string) (types.Capability, []byte, error)
ListCaps() ([]types.Capability, error)
}
// GithubRegistry is Registry's implementation treat github url as resource
type GithubRegistry struct {
URL string `json:"url"`
RegistryName string `json:"registry_name"`
client *github.Client
cfg *GithubContent
ctx context.Context
}
// NewRegistryFromConfig return Registry interface to get capabilities
func NewRegistryFromConfig(config apis.RegistryConfig) (Registry, error) {
return NewRegistry(context.TODO(), config.Token, config.Name, config.URL)
}
// NewRegistry will create a registry implementation
func NewRegistry(ctx context.Context, token, registryName string, regURL string) (Registry, error) {
tp, cfg, err := Parse(regURL)
if err != nil {
return nil, err
}
switch tp {
case TypeGithub:
var tc *http.Client
if token != "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc = oauth2.NewClient(ctx, ts)
}
return GithubRegistry{
URL: cfg.URL,
RegistryName: registryName,
client: github.NewClient(tc),
cfg: &cfg.GithubContent,
ctx: ctx,
}, nil
case TypeOss:
var tc http.Client
return OssRegistry{
Client: &tc,
BucketURL: fmt.Sprintf("https://%s/", cfg.BucketURL),
RegistryName: registryName,
}, nil
case TypeLocal:
_, err := os.Stat(cfg.AbsDir)
if os.IsNotExist(err) {
return LocalRegistry{}, err
}
return LocalRegistry{
AbsPath: cfg.AbsDir,
RegistryName: registryName,
}, nil
case TypeUnknown:
return nil, fmt.Errorf("not supported url")
}
return nil, fmt.Errorf("not supported url")
}
// ListRegistryConfig will get all registry config stored in local
// this will return at least one config, which is DefaultRegistry
func ListRegistryConfig() ([]apis.RegistryConfig, error) {
defaultRegistryConfig := apis.RegistryConfig{Name: DefaultRegistry, URL: "oss://registry.kubevela.net/"}
config, err := system.GetRepoConfig()
if err != nil {
return nil, err
}
data, err := os.ReadFile(filepath.Clean(config))
if err != nil {
if os.IsNotExist(err) {
err := StoreRepos([]apis.RegistryConfig{defaultRegistryConfig})
if err != nil {
return nil, errors.Wrap(err, "error initialize default registry")
}
return ListRegistryConfig()
}
return nil, err
}
var regConfigs []apis.RegistryConfig
if err = yaml.Unmarshal(data, &regConfigs); err != nil {
return nil, err
}
haveDefault := false
for _, r := range regConfigs {
if r.URL == defaultRegistryConfig.URL {
haveDefault = true
break
}
}
if !haveDefault {
regConfigs = append(regConfigs, defaultRegistryConfig)
}
return regConfigs, nil
}
// GetRegistry get a Registry implementation by name
func GetRegistry(regName string) (Registry, error) {
regConfigs, err := ListRegistryConfig()
if err != nil {
return nil, err
}
for _, conf := range regConfigs {
if conf.Name == regName {
return NewRegistryFromConfig(conf)
}
}
return nil, errors.Errorf("registry %s not found", regName)
}
// GetName will return registry name
func (g GithubRegistry) GetName() string {
return g.RegistryName
}
// GetURL will return github registry url
func (g GithubRegistry) GetURL() string {
return g.cfg.URL
}
// ListCaps list all capabilities of registry
func (g GithubRegistry) ListCaps() ([]types.Capability, error) {
var addons []types.Capability
itemContents, err := g.getRepoFile()
if err != nil {
return []types.Capability{}, err
}
for _, item := range itemContents {
capa, err := item.toCapability()
if err != nil {
fmt.Printf("parse definition of %s err %v\n", item.name, err)
continue
}
addons = append(addons, capa)
}
return addons, nil
}
// GetCap return capability object and raw data specified by cap name
func (g GithubRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
fileContent, _, _, err := g.client.Repositories.GetContents(context.Background(), g.cfg.Owner, g.cfg.Repo, fmt.Sprintf("%s/%s.yaml", g.cfg.Path, addonName), &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
if err != nil {
return types.Capability{}, []byte{}, err
}
var data []byte
if *fileContent.Encoding == "base64" {
data, err = base64.StdEncoding.DecodeString(*fileContent.Content)
if err != nil {
fmt.Printf("decode github content %s err %s\n", fileContent.GetPath(), err)
}
}
repoFile := RegistryFile{
data: data,
name: *fileContent.Name,
}
capa, err := repoFile.toCapability()
if err != nil {
return types.Capability{}, []byte{}, err
}
capa.Source = &types.Source{RepoName: g.RegistryName}
return capa, data, nil
}
func (g *GithubRegistry) getRepoFile() ([]RegistryFile, error) {
var items []RegistryFile
_, dirs, _, err := g.client.Repositories.GetContents(g.ctx, g.cfg.Owner, g.cfg.Repo, g.cfg.Path, &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
if err != nil {
return []RegistryFile{}, err
}
for _, repoItem := range dirs {
if *repoItem.Type != "file" {
continue
}
fileContent, _, _, err := g.client.Repositories.GetContents(g.ctx, g.cfg.Owner, g.cfg.Repo, *repoItem.Path, &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
if err != nil {
fmt.Printf("Getting content URL %s error: %s\n", repoItem.GetURL(), err)
continue
}
var data []byte
if *fileContent.Encoding == "base64" {
data, err = base64.StdEncoding.DecodeString(*fileContent.Content)
if err != nil {
fmt.Printf("decode github content %s err %s\n", fileContent.GetPath(), err)
continue
}
}
items = append(items, RegistryFile{
data: data,
name: *fileContent.Name,
})
}
return items, nil
}
// OssRegistry is Registry's implementation treat OSS url as resource
type OssRegistry struct {
*http.Client `json:"-"`
BucketURL string `json:"bucket_url"`
RegistryName string `json:"registry_name"`
}
// GetName return name of OssRegistry
func (o OssRegistry) GetName() string {
return o.RegistryName
}
// GetURL return URL of OssRegistry's bucket
func (o OssRegistry) GetURL() string {
return o.BucketURL
}
// GetCap return capability object and raw data specified by cap name
func (o OssRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
filename := addonName + ".yaml"
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
o.BucketURL+filename,
nil,
)
resp, err := o.Client.Do(req)
if err != nil {
return types.Capability{}, nil, err
}
data, err := io.ReadAll(resp.Body)
_ = resp.Body.Close()
if err != nil {
return types.Capability{}, nil, err
}
rf := RegistryFile{
data: data,
name: filename,
}
capa, err := rf.toCapability()
if err != nil {
return types.Capability{}, nil, err
}
capa.Source = &types.Source{RepoName: o.RegistryName}
return capa, data, nil
}
// ListCaps list all capabilities of registry
func (o OssRegistry) ListCaps() ([]types.Capability, error) {
rfs, err := o.getRegFiles()
if err != nil {
return []types.Capability{}, errors.Wrap(err, "Get raw files fail")
}
capas := make([]types.Capability, 0)
for _, rf := range rfs {
capa, err := rf.toCapability()
if err != nil {
fmt.Printf("[WARN] Parse file %s fail: %s\n", rf.name, err.Error())
}
capas = append(capas, capa)
}
return capas, nil
}
func (o OssRegistry) getRegFiles() ([]RegistryFile, error) {
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
o.BucketURL+"?list-type=2",
nil,
)
resp, err := o.Client.Do(req)
if err != nil {
return []RegistryFile{}, err
}
data, err := io.ReadAll(resp.Body)
_ = resp.Body.Close()
if err != nil {
return []RegistryFile{}, err
}
list := &ListBucketResult{}
err = xml.Unmarshal(data, list)
if err != nil {
return []RegistryFile{}, err
}
rfs := make([]RegistryFile, 0)
for _, fileName := range list.File {
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
o.BucketURL+fileName,
nil,
)
resp, err := o.Client.Do(req)
if err != nil {
fmt.Printf("[WARN] %s download fail\n", fileName)
continue
}
data, _ := io.ReadAll(resp.Body)
_ = resp.Body.Close()
rf := RegistryFile{
data: data,
name: fileName,
}
rfs = append(rfs, rf)
}
return rfs, nil
}
// LocalRegistry is Registry's implementation treat local url as resource
type LocalRegistry struct {
AbsPath string `json:"abs_path"`
RegistryName string `json:"registry_name"`
}
// GetName return name of LocalRegistry
func (l LocalRegistry) GetName() string {
return l.RegistryName
}
// GetURL return path of LocalRegistry
func (l LocalRegistry) GetURL() string {
return l.AbsPath
}
// GetCap return capability object and raw data specified by cap name
func (l LocalRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
fileName := addonName + ".yaml"
filePath := fmt.Sprintf("%s/%s", l.AbsPath, fileName)
data, err := os.ReadFile(filePath)
if err != nil {
return types.Capability{}, []byte{}, err
}
file := RegistryFile{
data: data,
name: fileName,
}
capa, err := file.toCapability()
if err != nil {
return types.Capability{}, []byte{}, err
}
capa.Source = &types.Source{RepoName: l.RegistryName}
return capa, data, nil
}
// ListCaps list all capabilities of registry
func (l LocalRegistry) ListCaps() ([]types.Capability, error) {
glob := filepath.Join(filepath.Clean(l.AbsPath), "*")
files, _ := filepath.Glob(glob)
capas := make([]types.Capability, 0)
for _, file := range files {
// nolint:gosec
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
capa, err := RegistryFile{
data: data,
name: path.Base(file),
}.toCapability()
if err != nil {
fmt.Printf("parsing file: %s err: %s\n", file, err)
continue
}
capas = append(capas, capa)
}
return capas, nil
}
func (item RegistryFile) toCapability() (types.Capability, error) {
dm, err := (&common.Args{}).GetDiscoveryMapper()
if err != nil {
return types.Capability{}, err
}
capability, err := ParseCapability(dm, item.data)
if err != nil {
return types.Capability{}, err
}
return capability, nil
}
// RegistryFile describes a file item in registry
type RegistryFile struct {
data []byte // file content
name string // file's name
}
// ListBucketResult describe a file list from OSS
type ListBucketResult struct {
File []string `xml:"Contents>Key"`
Count int `xml:"KeyCount"`
}
// Content contains different type of content needed when building Registry
type Content struct {
OssContent
GithubContent
LocalContent
}
// LocalContent for local registry
type LocalContent struct {
AbsDir string `json:"abs_dir"`
}
// OssContent for oss registry
type OssContent struct {
BucketURL string `json:"bucket_url"`
}
// GithubContent for registry
type GithubContent struct {
URL string `json:"url"`
Owner string `json:"owner"`
Repo string `json:"repo"`
Path string `json:"path"`
Ref string `json:"ref"`
}
// TypeLocal represents github
const TypeLocal = "local"
// TypeOss represent oss
const TypeOss = "oss"
// TypeGithub represents github
const TypeGithub = "github"
// TypeUnknown represents parse failed
const TypeUnknown = "unknown"
// Parse will parse config from address
func Parse(addr string) (string, *Content, error) {
URL, err := url.Parse(addr)
if err != nil {
return "", nil, err
}
l := strings.Split(strings.TrimPrefix(URL.Path, "/"), "/")
switch URL.Scheme {
case "http", "https":
switch URL.Host {
case "github.com":
// We support two valid format:
// 1. https://github.com/<owner>/<repo>/tree/<branch>/<path-to-dir>
// 2. https://github.com/<owner>/<repo>/<path-to-dir>
if len(l) < 3 {
return "", nil, errors.New("invalid format " + addr)
}
if l[2] == "tree" {
// https://github.com/<owner>/<repo>/tree/<branch>/<path-to-dir>
if len(l) < 5 {
return "", nil, errors.New("invalid format " + addr)
}
return TypeGithub, &Content{
GithubContent: GithubContent{
URL: addr,
Owner: l[0],
Repo: l[1],
Path: strings.Join(l[4:], "/"),
Ref: l[3],
},
}, nil
}
// https://github.com/<owner>/<repo>/<path-to-dir>
return TypeGithub, &Content{
GithubContent: GithubContent{
URL: addr,
Owner: l[0],
Repo: l[1],
Path: strings.Join(l[2:], "/"),
Ref: "", // use default branch
},
},
nil
case "api.github.com":
if len(l) != 5 {
return "", nil, errors.New("invalid format " + addr)
}
//https://api.github.com/repos/<owner>/<repo>/contents/<path-to-dir>
return TypeGithub, &Content{
GithubContent: GithubContent{
URL: addr,
Owner: l[1],
Repo: l[2],
Path: l[4],
Ref: URL.Query().Get("ref"),
},
},
nil
default:
}
case "oss":
return TypeOss, &Content{
OssContent: OssContent{
BucketURL: URL.Host,
},
}, nil
case "file":
return TypeLocal, &Content{
LocalContent: LocalContent{
AbsDir: URL.Path,
},
}, nil
}
return TypeUnknown, nil, nil
}
// StoreRepos will store registry repo locally
func StoreRepos(registries []apis.RegistryConfig) error {
config, err := system.GetRepoConfig()
if err != nil {
return err
}
data, err := yaml.Marshal(registries)
if err != nil {
return err
}
//nolint:gosec
return os.WriteFile(config, data, 0644)
}
// ParseCapability will convert config from remote center to capability
func ParseCapability(mapper discoverymapper.DiscoveryMapper, data []byte) (types.Capability, error) {
var obj = unstructured.Unstructured{Object: make(map[string]interface{})}
err := yaml.Unmarshal(data, &obj.Object)
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)
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)
case "ScopeDefinition":
// TODO(wonderflow): support scope definition here.
}
return types.Capability{}, fmt.Errorf("unknown definition Type %s", obj.GetKind())
}