Feat: addon support version check (#3304)

* addon support version check

add more tests

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

* add kubernetes tests

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

* add more tests

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

* reorgnize the check logic

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

* fix addon error bug in apiserver

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

fix comments

fix test

* add err addon bcode

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

* fix comments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
This commit is contained in:
wyike
2022-02-23 12:17:31 +08:00
committed by GitHub
parent 7059c8df79
commit 16414a0d9f
13 changed files with 421 additions and 28 deletions
+2
View File
@@ -31,6 +31,8 @@ const (
DefaultAppNamespace = "default"
// AutoDetectWorkloadDefinition defines the default workload type for ComponentDefinition which doesn't specify a workload
AutoDetectWorkloadDefinition = "autodetects.core.oam.dev"
// KubeVelaControllerDeployment defines the KubeVela controller's deployment name
KubeVelaControllerDeployment = "kubevela-vela-core"
)
// DefaultKubeVelaNS defines the default KubeVela namespace in Kubernetes
+108 -1
View File
@@ -32,8 +32,10 @@ import (
"cuelang.org/go/cue"
cueyaml "cuelang.org/go/encoding/yaml"
"github.com/google/go-github/v32/github"
"github.com/hashicorp/go-version"
"github.com/pkg/errors"
"golang.org/x/oauth2"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -41,6 +43,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
k8syaml "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
types2 "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
@@ -60,6 +63,7 @@ import (
"github.com/oam-dev/kubevela/pkg/utils"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/utils/common"
version2 "github.com/oam-dev/kubevela/version"
)
const (
@@ -865,10 +869,11 @@ type Installer struct {
registryMeta map[string]SourceMeta
args map[string]interface{}
cache *Cache
dc *discovery.DiscoveryClient
}
// NewAddonInstaller will create an installer for addon
func NewAddonInstaller(ctx context.Context, cli client.Client, apply apply.Applicator, config *rest.Config, r *Registry, args map[string]interface{}, cache *Cache) Installer {
func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r *Registry, args map[string]interface{}, cache *Cache) Installer {
return Installer{
ctx: ctx,
config: config,
@@ -877,12 +882,18 @@ func NewAddonInstaller(ctx context.Context, cli client.Client, apply apply.Appli
r: r,
args: args,
cache: cache,
dc: discoveryClient,
}
}
func (h *Installer) enableAddon(addon *InstallPackage) error {
var err error
h.addon = addon
err = checkAddonVersionMeetRequired(h.ctx, addon.SystemRequirements, h.cli, h.dc)
if err != nil {
return ErrVersionMismatch
}
if err = h.installDependency(addon); err != nil {
return err
}
@@ -1104,3 +1115,99 @@ func FetchAddonRelatedApp(ctx context.Context, cli client.Client, addonName stri
}
return app, nil
}
// checkAddonVersionMeetRequired will check the version of cli/ux and kubevela-core-controller whether meet the addon requirement, if not will return an error
// please notice that this func is for check production environment which vela cli/ux or vela core is officalVersion
// if version is for test or debug eg: latest/commit-id/branch-name this func will return nil error
func checkAddonVersionMeetRequired(ctx context.Context, require *SystemRequirements, k8sClient client.Client, dc *discovery.DiscoveryClient) error {
if require == nil {
return nil
}
// if not semver version, bypass check cli/ux. eg: {branch name/git commit id/UNKNOWN}
if version2.IsOfficialKubeVelaVersion(version2.VelaVersion) {
res, err := checkSemVer(version2.VelaVersion, require.VelaVersion)
if err != nil {
return err
}
if !res {
return fmt.Errorf("vela cli/ux version: %s cannot meet requirement", version2.VelaVersion)
}
}
// check vela core controller version
imageVersion, err := fetchVelaCoreImageTag(ctx, k8sClient)
if err != nil {
return err
}
// if not semver version, bypass check vela-core.
if version2.IsOfficialKubeVelaVersion(imageVersion) {
res, err := checkSemVer(imageVersion, require.VelaVersion)
if err != nil {
return err
}
if !res {
return fmt.Errorf("the vela core controller: %s cannot meet requirement ", imageVersion)
}
}
// discovery client is nil so bypass check kubernetes version
if dc == nil {
return nil
}
k8sVersion, err := dc.ServerVersion()
if err != nil {
return err
}
// if not semver version, bypass check kubernetes version.
if version2.IsOfficialKubeVelaVersion(k8sVersion.GitVersion) {
res, err := checkSemVer(k8sVersion.GitVersion, require.KubernetesVersion)
if err != nil {
return err
}
if !res {
return fmt.Errorf("the kubernetes version %s cannot meet requirement", k8sVersion.GitVersion)
}
}
return nil
}
func checkSemVer(actual string, require string) (bool, error) {
if len(require) == 0 {
return true, nil
}
smeVer := strings.TrimPrefix(actual, "v")
l := strings.ReplaceAll(require, "v", " ")
constraint, err := version.NewConstraint(l)
if err != nil {
return false, err
}
v, err := version.NewVersion(smeVer)
if err != nil {
return false, err
}
return constraint.Check(v), nil
}
func fetchVelaCoreImageTag(ctx context.Context, k8sClient client.Client) (string, error) {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, types2.NamespacedName{Namespace: types.DefaultKubeVelaNS, Name: types.KubeVelaControllerDeployment}, deploy); err != nil {
return "", err
}
var tag string
for _, c := range deploy.Spec.Template.Spec.Containers {
if c.Name == types.DefaultKubeVelaReleaseName {
l := strings.Split(c.Image, ":")
if len(l) == 1 {
// if tag is empty mean use latest image
return "latest", nil
}
tag = l[1]
}
}
return tag, nil
}
+97
View File
@@ -21,6 +21,8 @@ import (
"fmt"
"time"
appsv1 "k8s.io/api/apps/v1"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -30,6 +32,8 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("Addon test", func() {
@@ -176,6 +180,47 @@ var _ = Describe("Addon test", func() {
})
})
var _ = Describe("Addon func test", func() {
var deploy appsv1.Deployment
AfterEach(func() {
Expect(k8sClient.Delete(ctx, &deploy))
})
It("fetchVelaCoreImageTag func test", func() {
deploy = appsv1.Deployment{}
tag, err := fetchVelaCoreImageTag(ctx, k8sClient)
Expect(err).Should(util.NotFoundMatcher{})
Expect(tag).Should(BeEquivalentTo(""))
Expect(yaml.Unmarshal([]byte(deployYaml), &deploy)).Should(BeNil())
deploy.SetNamespace(types.DefaultKubeVelaNS)
Expect(k8sClient.Create(ctx, &deploy)).Should(BeNil())
Eventually(func() error {
tag, err := fetchVelaCoreImageTag(ctx, k8sClient)
if err != nil {
return err
}
if tag != "v1.2.3" {
return fmt.Errorf("tag missmatch want %s actual %s", "v1.2.3", tag)
}
return err
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
})
It("checkAddonVersionMeetRequired func test", func() {
deploy = appsv1.Deployment{}
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.1"}, k8sClient, dc)).Should(util.NotFoundMatcher{})
Expect(yaml.Unmarshal([]byte(deployYaml), &deploy)).Should(BeNil())
deploy.SetNamespace(types.DefaultKubeVelaNS)
Expect(k8sClient.Create(ctx, &deploy)).Should(BeNil())
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.1"}, k8sClient, dc)).Should(BeNil())
Expect(checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=v1.2.4"}, k8sClient, dc)).ShouldNot(BeNil())
})
})
const (
appYaml = `apiVersion: core.oam.dev/v1beta1
kind: Application
@@ -201,4 +246,56 @@ spec:
image: crccheck/hello-world
port: 8000
`
deployYaml = `apiVersion: apps/v1
kind: Deployment
metadata:
name: kubevela-vela-core
namespace: vela-system
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/instance: kubevela
app.kubernetes.io/name: vela-core
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "8080"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/instance: kubevela
app.kubernetes.io/name: vela-core
spec:
containers:
- args:
image: oamdev/vela-core:v1.2.3
imagePullPolicy: Always
name: kubevela
ports:
- containerPort: 9443
name: webhook-server
protocol: TCP
- containerPort: 9440
name: healthz
protocol: TCP
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 50m
memory: 20Mi
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30`
)
+96
View File
@@ -20,6 +20,7 @@ import (
"context"
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
"net/http/httptest"
"os"
@@ -27,6 +28,8 @@ import (
"strings"
"testing"
version2 "github.com/oam-dev/kubevela/version"
"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/google/go-github/v32/github"
v1alpha12 "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
@@ -651,3 +654,96 @@ func TestGitLabReaderNotPanic(t *testing.T) {
_, err := NewAsyncReader("https://gitlab.com/test/catalog", "", "addons", "", gitType)
assert.EqualError(t, err, "git type repository only support github for now")
}
func TestCheckSemVer(t *testing.T) {
testCases := []struct {
actual string
require string
nilError bool
res bool
}{
{
actual: "v1.2.1",
require: "<=v1.2.1",
res: true,
},
{
actual: "v1.2.1",
require: ">v1.2.1",
res: false,
},
{
actual: "v1.2.1",
require: "<=v1.2.3",
res: true,
},
{
actual: "v1.2",
require: "<=v1.2.3",
res: true,
},
{
actual: "v1.2.1",
require: ">v1.2.3",
res: false,
},
{
actual: "v1.2.1",
require: "=v1.2.1",
res: true,
},
{
actual: "1.2.1",
require: "=v1.2.1",
res: true,
},
{
actual: "1.2.1",
require: "",
res: true,
},
{
actual: "v1.2.2",
require: "<=v1.2.3, >=v1.2.1",
res: true,
},
{
actual: "v1.2.0",
require: "v1.2.0, <=v1.2.3",
res: true,
},
{
actual: "1.2.2",
require: "v1.2.2",
res: true,
},
{
actual: "1.2.02",
require: "v1.2.2",
res: true,
},
}
for _, testCase := range testCases {
result, err := checkSemVer(testCase.actual, testCase.require)
assert.NoError(t, err)
assert.Equal(t, result, testCase.res)
}
}
func TestCheckAddonVersionMeetRequired(t *testing.T) {
k8sClient := &test.MockClient{
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
return nil
}),
}
ctx := context.Background()
assert.NoError(t, checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=1.2.4"}, k8sClient, nil))
version2.VelaVersion = "v1.2.3"
if err := checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=1.2.4"}, k8sClient, nil); err == nil {
assert.Error(t, fmt.Errorf("should meet error"))
}
version2.VelaVersion = "v1.2.4"
assert.NoError(t, checkAddonVersionMeetRequired(ctx, &SystemRequirements{VelaVersion: ">=1.2.4"}, k8sClient, nil))
}
+3
View File
@@ -35,6 +35,9 @@ var (
// ErrNotExist means addon not exists
ErrNotExist = NewAddonError("addon not exist")
// ErrVersionMismatch means addon version requirement mismatch
ErrVersionMismatch = NewAddonError("addon version requirements mismatch")
)
// WrapErrRateLimit return ErrRateLimit if is the situation, or return error directly
+6 -4
View File
@@ -21,6 +21,8 @@ import (
"encoding/json"
"fmt"
"k8s.io/client-go/discovery"
"k8s.io/klog/v2"
v1 "k8s.io/api/core/v1"
@@ -49,8 +51,8 @@ const (
)
// EnableAddon will enable addon with dependency check, source is where addon from.
func EnableAddon(ctx context.Context, name string, cli client.Client, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache) error {
h := NewAddonInstaller(ctx, cli, apply, config, &r, args, cache)
func EnableAddon(ctx context.Context, name string, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache) error {
h := NewAddonInstaller(ctx, cli, discoveryClient, apply, config, &r, args, cache)
pkg, err := h.loadInstallPackage(name)
if err != nil {
return err
@@ -76,7 +78,7 @@ func DisableAddon(ctx context.Context, cli client.Client, name string) error {
}
// EnableAddonByLocalDir enable an addon from local dir
func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli client.Client, applicator apply.Applicator, config *rest.Config, args map[string]interface{}) error {
func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli client.Client, dc *discovery.DiscoveryClient, applicator apply.Applicator, config *rest.Config, args map[string]interface{}) error {
r := localReader{dir: dir, name: name}
metas, err := r.ListAddonMeta()
if err != nil {
@@ -91,7 +93,7 @@ func EnableAddonByLocalDir(ctx context.Context, name string, dir string, cli cli
if err != nil {
return err
}
h := NewAddonInstaller(ctx, cli, applicator, config, &Registry{Name: LocalAddonRegistryName}, args, nil)
h := NewAddonInstaller(ctx, cli, dc, applicator, config, &Registry{Name: LocalAddonRegistryName}, args, nil)
needEnableAddonNames, err := h.checkDependency(pkg)
if err != nil {
return err
+8
View File
@@ -21,6 +21,8 @@ import (
"testing"
"time"
"k8s.io/client-go/discovery"
v12 "k8s.io/api/core/v1"
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -49,6 +51,7 @@ var testEnv *envtest.Environment
var dm discoverymapper.DiscoveryMapper
var pd *packages.PackageDiscover
var testns string
var dc *discovery.DiscoveryClient
func TestAddon(t *testing.T) {
RegisterFailHandler(Fail)
@@ -79,6 +82,11 @@ var _ = BeforeSuite(func(done Done) {
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
dc, err = discovery.NewDiscoveryClientForConfig(cfg)
Expect(err).ToNot(HaveOccurred())
Expect(dc).ShouldNot(BeNil())
dm, err = discoverymapper.New(cfg)
Expect(err).ToNot(HaveOccurred())
Expect(dm).ToNot(BeNil())
+17 -10
View File
@@ -54,16 +54,17 @@ type InstallPackage struct {
// Meta defines the format for a single addon
type Meta struct {
Name string `json:"name" validate:"required"`
Version string `json:"version"`
Description string `json:"description"`
Icon string `json:"icon"`
URL string `json:"url,omitempty"`
Tags []string `json:"tags,omitempty"`
DeployTo *DeployTo `json:"deployTo,omitempty"`
Dependencies []*Dependency `json:"dependencies,omitempty"`
NeedNamespace []string `json:"needNamespace,omitempty"`
Invisible bool `json:"invisible"`
Name string `json:"name" validate:"required"`
Version string `json:"version"`
Description string `json:"description"`
Icon string `json:"icon"`
URL string `json:"url,omitempty"`
Tags []string `json:"tags,omitempty"`
DeployTo *DeployTo `json:"deployTo,omitempty"`
Dependencies []*Dependency `json:"dependencies,omitempty"`
NeedNamespace []string `json:"needNamespace,omitempty"`
Invisible bool `json:"invisible"`
SystemRequirements *SystemRequirements `json:"system,omitempty"`
}
// DeployTo defines where the addon to deploy to
@@ -84,3 +85,9 @@ type ElementFile struct {
Data string
Name string
}
// SystemRequirements is this addon need version
type SystemRequirements struct {
VelaVersion string `json:"vela,omitempty"`
KubernetesVersion string `json:"kubernetes,omitempty"`
}
+14
View File
@@ -17,6 +17,7 @@ limitations under the License.
package clients
import (
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
@@ -84,3 +85,16 @@ func GetPackageDiscover() (*packages.PackageDiscover, error) {
}
return pd, nil
}
// GetDiscoveryClient return a discovery client
func GetDiscoveryClient() (*discovery.DiscoveryClient, error) {
conf, err := GetKubeConfig()
if err != nil {
return nil, err
}
dc, err := discovery.NewDiscoveryClientForConfig(conf)
if err != nil {
return nil, err
}
return dc, nil
}
+29 -5
View File
@@ -26,6 +26,8 @@ import (
"sync"
"time"
"k8s.io/client-go/discovery"
k8stypes "k8s.io/apimachinery/pkg/types"
v1 "k8s.io/api/core/v1"
@@ -101,6 +103,10 @@ func NewAddonUsecase(cacheTime time.Duration) AddonHandler {
if err != nil {
panic(err)
}
dc, err := clients.GetDiscoveryClient()
if err != nil {
panic(err)
}
ds := pkgaddon.NewRegistryDataStore(kubecli)
cache := pkgaddon.NewCache(ds)
@@ -114,6 +120,7 @@ func NewAddonUsecase(cacheTime time.Duration) AddonHandler {
config: config,
apply: apply.NewAPIApplicator(kubecli),
mutex: new(sync.RWMutex),
discoveryClient: dc,
}
}
@@ -123,6 +130,7 @@ type defaultAddonHandler struct {
kubeClient client.Client
config *rest.Config
apply apply.Applicator
discoveryClient *discovery.DiscoveryClient
mutex *sync.RWMutex
}
@@ -352,15 +360,23 @@ func (u *defaultAddonHandler) EnableAddon(ctx context.Context, name string, args
return err
}
for _, r := range registries {
err = pkgaddon.EnableAddon(ctx, name, u.kubeClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
err = pkgaddon.EnableAddon(ctx, name, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
if err == nil {
return nil
}
if err != nil && errors.As(err, &pkgaddon.ErrNotExist) {
// if reach this line error must is not nil
if errors.Is(err, pkgaddon.ErrNotExist) {
// one registry return addon not exist error, should not break other registry func
continue
}
// wrap this error with special bcode
if errors.Is(err, pkgaddon.ErrVersionMismatch) {
return bcode.ErrAddonSystemVersionMismatch
}
// except `addon not found`, other errors should return directly
return err
}
return bcode.ErrAddonNotExist
}
@@ -412,13 +428,21 @@ func (u *defaultAddonHandler) UpdateAddon(ctx context.Context, name string, args
}
for _, r := range registries {
err = pkgaddon.EnableAddon(ctx, name, u.kubeClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
err = pkgaddon.EnableAddon(ctx, name, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache)
if err == nil {
return nil
}
if err != nil && !errors.Is(err, pkgaddon.ErrNotExist) {
return bcode.WrapGithubRateLimitErr(err)
if errors.Is(err, pkgaddon.ErrNotExist) {
continue
}
// wrap this error with special bcode
if errors.Is(err, pkgaddon.ErrVersionMismatch) {
return bcode.ErrAddonSystemVersionMismatch
}
// except `addon not found`, other errors should return directly
return err
}
return bcode.ErrAddonNotExist
}
@@ -61,6 +61,9 @@ var (
// ErrAddonDependencyNotSatisfy means addon's dependencies is not enabled
ErrAddonDependencyNotSatisfy = NewBcode(500, 50017, "addon's dependencies is not enabled")
// ErrAddonSystemVersionMismatch means addon's version required mismatch
ErrAddonSystemVersionMismatch = NewBcode(400, 50018, "addon's system version requirement mismatch")
)
// isGithubRateLimit check if error is github rate limit
+20
View File
@@ -19,6 +19,8 @@ package common
import (
"fmt"
"k8s.io/client-go/discovery"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/flowcontrol"
@@ -36,6 +38,7 @@ type Args struct {
client client.Client
dm discoverymapper.DiscoveryMapper
pd *packages.PackageDiscover
dc *discovery.DiscoveryClient
}
// SetConfig insert kubeconfig into Args
@@ -122,3 +125,20 @@ func (a *Args) GetPackageDiscover() (*packages.PackageDiscover, error) {
a.pd = pd
return pd, nil
}
// GetDiscoveryClient return a discovery client from cli args
func (a *Args) GetDiscoveryClient() (*discovery.DiscoveryClient, error) {
if a.dc != nil {
return a.dc, nil
}
cfg, err := a.GetConfig()
if err != nil {
return nil, err
}
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
if err != nil {
return nil, err
}
return dc, nil
}
+18 -8
View File
@@ -24,6 +24,8 @@ import (
"strings"
"time"
"k8s.io/client-go/discovery"
"helm.sh/helm/v3/pkg/strvals"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
@@ -134,6 +136,10 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
if err != nil {
return err
}
dc, err := c.GetDiscoveryClient()
if err != nil {
return err
}
addonOrDir := args[0]
var name = addonOrDir
if file, err := os.Stat(addonOrDir); err == nil {
@@ -143,7 +149,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
ioStream.Infof("enable addon by local dir: %s \n", addonOrDir)
// args[0] is a local path install with local dir, use base dir name as addonName
name = filepath.Base(addonOrDir)
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, config, addonArgs)
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
if err != nil {
return err
}
@@ -152,7 +158,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
return fmt.Errorf("addon directory %s not found in local", addonOrDir)
}
err = enableAddon(ctx, k8sClient, config, name, addonArgs)
err = enableAddon(ctx, k8sClient, dc, config, name, addonArgs)
if err != nil {
return err
}
@@ -204,6 +210,10 @@ func NewAddonUpgradeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Co
if err != nil {
return err
}
dc, err := c.GetDiscoveryClient()
if err != nil {
return err
}
addonArgs, err := parseToMap(args[1:])
if err != nil {
return err
@@ -221,7 +231,7 @@ func NewAddonUpgradeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Co
if err != nil {
return errors.Wrapf(err, "cannot fetch addon related addon %s", name)
}
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, config, addonArgs)
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
if err != nil {
return err
}
@@ -234,7 +244,7 @@ func NewAddonUpgradeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Co
if err != nil {
return errors.Wrapf(err, "cannot fetch addon related addon %s", addonOrDir)
}
err = enableAddon(ctx, k8sClient, config, addonOrDir, addonArgs)
err = enableAddon(ctx, k8sClient, dc, config, addonOrDir, addonArgs)
if err != nil {
return err
}
@@ -305,7 +315,7 @@ func NewAddonStatusCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
}
}
func enableAddon(ctx context.Context, k8sClient client.Client, config *rest.Config, name string, args map[string]interface{}) error {
func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, name string, args map[string]interface{}) error {
var err error
registryDS := pkgaddon.NewRegistryDataStore(k8sClient)
registries, err := registryDS.ListRegistries(ctx)
@@ -314,7 +324,7 @@ func enableAddon(ctx context.Context, k8sClient client.Client, config *rest.Conf
}
for _, registry := range registries {
err = pkgaddon.EnableAddon(ctx, name, k8sClient, apply.NewAPIApplicator(k8sClient), config, registry, args, nil)
err = pkgaddon.EnableAddon(ctx, name, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil)
if errors.Is(err, pkgaddon.ErrNotExist) {
continue
}
@@ -330,8 +340,8 @@ func enableAddon(ctx context.Context, k8sClient client.Client, config *rest.Conf
}
// enableAddonByLocal enable addon in local dir and return the addon name
func enableAddonByLocal(ctx context.Context, name string, dir string, k8sClient client.Client, config *rest.Config, args map[string]interface{}) error {
if err := pkgaddon.EnableAddonByLocalDir(ctx, name, dir, k8sClient, apply.NewAPIApplicator(k8sClient), config, args); err != nil {
func enableAddonByLocal(ctx context.Context, name string, dir string, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, args map[string]interface{}) error {
if err := pkgaddon.EnableAddonByLocalDir(ctx, name, dir, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, args); err != nil {
return err
}
if err := waitApplicationRunning(k8sClient, name); err != nil {