mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-18 03:56:36 +00:00
Feat: support NOTES.cue in addon for additional info printer (#5195)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
This commit is contained in:
+105
-16
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/imdario/mergo"
|
||||
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -88,6 +89,12 @@ const (
|
||||
// AppTemplateCueFileName is the addon application template.cue file name
|
||||
AppTemplateCueFileName string = "template.cue"
|
||||
|
||||
// NotesCUEFileName is the addon notes print to end users when installed
|
||||
NotesCUEFileName string = "NOTES.cue"
|
||||
|
||||
// KeyWordNotes is the keyword in NOTES.cue which will render the notes message out.
|
||||
KeyWordNotes string = "notes"
|
||||
|
||||
// GlobalParameterFileName is the addon global parameter.cue file name
|
||||
GlobalParameterFileName string = "parameter.cue"
|
||||
|
||||
@@ -111,6 +118,9 @@ const (
|
||||
|
||||
// DefaultGiteeURL is the addon repository of gitee api
|
||||
DefaultGiteeURL string = "https://gitee.com/api/v5/"
|
||||
|
||||
// InstallerRuntimeOption inject install runtime info into addon options
|
||||
InstallerRuntimeOption string = "installerRuntimeOption"
|
||||
)
|
||||
|
||||
// ParameterFileName is the addon resources/parameter.cue file name
|
||||
@@ -153,10 +163,17 @@ type Pattern struct {
|
||||
|
||||
// Patterns is the file pattern that the addon should be in
|
||||
var Patterns = []Pattern{
|
||||
// config-templates pattern
|
||||
{IsDir: true, Value: ConfigTemplateDirName},
|
||||
// single file reader pattern
|
||||
{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName},
|
||||
{Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName},
|
||||
{IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName}, {Value: AppTemplateCueFileName}, {Value: GlobalParameterFileName}, {Value: LegacyReadmeFileName}}
|
||||
// parameter in resource directory
|
||||
{Value: ParameterFileName},
|
||||
// directory files
|
||||
{IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName}, {IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName},
|
||||
// CUE app template, parameter and notes
|
||||
{Value: AppTemplateCueFileName}, {Value: GlobalParameterFileName}, {Value: NotesCUEFileName},
|
||||
{Value: LegacyReadmeFileName}}
|
||||
|
||||
// GetPatternFromItem will check if the file path has a valid pattern, return empty string if it's invalid.
|
||||
// AsyncReader is needed to calculate relative path
|
||||
@@ -282,6 +299,7 @@ func GetInstallPackageFromReader(r AsyncReader, meta *SourceMeta, uiData *UIData
|
||||
DefSchemaName: readDefSchemaFile,
|
||||
ViewDirName: readViewFile,
|
||||
AppTemplateCueFileName: readAppCueTemplate,
|
||||
NotesCUEFileName: readNotesFile,
|
||||
}
|
||||
ptItems := ClassifyItemByPattern(meta, r)
|
||||
|
||||
@@ -342,6 +360,16 @@ func readParamFile(a *UIData, reader AsyncReader, readPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// readNotesFile read single NOTES.cue file
|
||||
func readNotesFile(a *InstallPackage, reader AsyncReader, readPath string) error {
|
||||
data, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Notes = ElementFile{Data: data, Name: filepath.Base(readPath)}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readGlobalParamFile read global parameter file.
|
||||
func readGlobalParamFile(a *UIData, reader AsyncReader, readPath string) error {
|
||||
b, err := reader.ReadFile(readPath)
|
||||
@@ -842,11 +870,16 @@ type Installer struct {
|
||||
dryRun bool
|
||||
dryRunBuff *bytes.Buffer
|
||||
|
||||
installerRuntime map[string]interface{}
|
||||
|
||||
registries []Registry
|
||||
}
|
||||
|
||||
// NewAddonInstaller will create an installer for addon
|
||||
func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r *Registry, args map[string]interface{}, cache *Cache, registries []Registry, opts ...InstallOption) Installer {
|
||||
if args == nil {
|
||||
args = map[string]interface{}{}
|
||||
}
|
||||
i := Installer{
|
||||
ctx: ctx,
|
||||
config: config,
|
||||
@@ -859,13 +892,22 @@ func NewAddonInstaller(ctx context.Context, cli client.Client, discoveryClient *
|
||||
dryRunBuff: &bytes.Buffer{},
|
||||
registries: registries,
|
||||
}
|
||||
ir := args[InstallerRuntimeOption]
|
||||
if irr, ok := ir.(map[string]interface{}); ok {
|
||||
i.installerRuntime = irr
|
||||
} else {
|
||||
i.installerRuntime = map[string]interface{}{}
|
||||
}
|
||||
// clean injected data from runtime option
|
||||
delete(args, InstallerRuntimeOption)
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (h *Installer) enableAddon(addon *InstallPackage) error {
|
||||
func (h *Installer) enableAddon(addon *InstallPackage) (string, error) {
|
||||
var err error
|
||||
h.addon = addon
|
||||
|
||||
@@ -873,22 +915,28 @@ func (h *Installer) enableAddon(addon *InstallPackage) error {
|
||||
err = checkAddonVersionMeetRequired(h.ctx, addon.SystemRequirements, h.cli, h.dc)
|
||||
if err != nil {
|
||||
version := h.getAddonVersionMeetSystemRequirement(addon.Name)
|
||||
return VersionUnMatchError{addonName: addon.Name, err: err, userSelectedAddonVersion: addon.Version, availableVersion: version}
|
||||
return "", VersionUnMatchError{addonName: addon.Name, err: err, userSelectedAddonVersion: addon.Version, availableVersion: version}
|
||||
}
|
||||
}
|
||||
|
||||
if err = h.installDependency(addon); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if err = h.dispatchAddonResource(addon); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
// we shouldn't put continue func into dispatchAddonResource, because the re-apply app maybe already update app and
|
||||
// the suspend will set with false automatically
|
||||
if err := h.continueOrRestartWorkflow(); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
return nil
|
||||
additionalInfo, err := h.renderNotes(addon)
|
||||
if err != nil {
|
||||
klog.Warningf("fail to render notes for addon %s: %v\n", addon.Name, err)
|
||||
// notes don't affect the installation, so just print warn logs instead of abort with errors
|
||||
return "", nil
|
||||
}
|
||||
return additionalInfo, nil
|
||||
}
|
||||
|
||||
func (h *Installer) loadInstallPackage(name, version string) (*InstallPackage, error) {
|
||||
@@ -960,9 +1008,13 @@ func (h *Installer) installDependency(addon *InstallPackage) error {
|
||||
// try to install the dependent addon from the same registry with the current addon
|
||||
depAddon, err = h.loadInstallPackage(dep.Name, dep.Version)
|
||||
if err == nil {
|
||||
if err = depHandler.enableAddon(depAddon); err != nil {
|
||||
additionalInfo, err := depHandler.enableAddon(depAddon)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fail to dispatch dependent addon resource")
|
||||
}
|
||||
if len(additionalInfo) > 0 {
|
||||
klog.Infof("addon %s installed with additional info: %s\n", addon.Name, additionalInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !errors.Is(err, ErrNotExist) {
|
||||
@@ -983,9 +1035,13 @@ func (h *Installer) installDependency(addon *InstallPackage) error {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
if err = depHandler.enableAddon(depAddon); err != nil {
|
||||
additionalInfo, err := depHandler.enableAddon(depAddon)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fail to dispatch dependent addon resource")
|
||||
}
|
||||
if len(additionalInfo) > 0 {
|
||||
klog.Infof("addon %s installed with additional info: %s\n", addon.Name, additionalInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("dependency addon: %s with version: %s cannot be found from all registries", dep.Name, dep.Version)
|
||||
@@ -1016,14 +1072,16 @@ func (h *Installer) checkDependency(addon *InstallPackage) ([]string, error) {
|
||||
}
|
||||
return needEnable, nil
|
||||
}
|
||||
func (h *Installer) createOrUpdate(app *v1beta1.Application) error {
|
||||
|
||||
// createOrUpdate will return true if updated
|
||||
func (h *Installer) createOrUpdate(app *v1beta1.Application) (bool, error) {
|
||||
var getapp v1beta1.Application
|
||||
err := h.cli.Get(h.ctx, client.ObjectKey{Name: app.Name, Namespace: app.Namespace}, &getapp)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return h.cli.Create(h.ctx, app)
|
||||
return false, h.cli.Create(h.ctx, app)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
getapp.Spec = app.Spec
|
||||
getapp.Labels = app.Labels
|
||||
@@ -1031,10 +1089,10 @@ func (h *Installer) createOrUpdate(app *v1beta1.Application) error {
|
||||
err = h.cli.Update(h.ctx, &getapp)
|
||||
if err != nil {
|
||||
klog.Errorf("fail to create application: %v", err)
|
||||
return errors.Wrap(err, "fail to create application")
|
||||
return false, errors.Wrap(err, "fail to create application")
|
||||
}
|
||||
getapp.DeepCopyInto(app)
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
@@ -1096,10 +1154,13 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
h.dryRunBuff.Write(result)
|
||||
h.dryRunBuff.WriteString("\n")
|
||||
} else {
|
||||
err = h.createOrUpdate(app)
|
||||
updated, err := h.createOrUpdate(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if updated {
|
||||
h.installerRuntime["upgrade"] = true
|
||||
}
|
||||
}
|
||||
|
||||
auxiliaryOutputs = append(auxiliaryOutputs, defs...)
|
||||
@@ -1146,6 +1207,34 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Installer) renderNotes(addon *InstallPackage) (string, error) {
|
||||
r := addonCueTemplateRender{
|
||||
addon: addon,
|
||||
inputArgs: h.args,
|
||||
contextInfo: map[string]interface{}{
|
||||
"installer": h.installerRuntime,
|
||||
},
|
||||
}
|
||||
contextFile, err := r.formatContext()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
notesFile := addon.Notes.Data + "\n" + contextFile
|
||||
val, err := value.NewValue(notesFile, nil, "")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "build values for NOTES.cue")
|
||||
}
|
||||
notes, err := val.LookupValue(KeyWordNotes)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "look up notes in NOTES.cue")
|
||||
}
|
||||
notesStr, err := notes.CueValue().String()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "convert notes to string")
|
||||
}
|
||||
return notesStr, nil
|
||||
}
|
||||
|
||||
// this func will handle such two case
|
||||
// 1. if last apply failed an workflow have suspend, this func will continue the workflow
|
||||
// 2. restart the workflow, if the new cluster have been added in KubeVela
|
||||
|
||||
@@ -382,7 +382,7 @@ var _ = Describe("test enable addon in local dir", func() {
|
||||
|
||||
It("test enable addon by local dir", func() {
|
||||
ctx := context.Background()
|
||||
err := EnableAddonByLocalDir(ctx, "example", "./testdata/example", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
_, err := EnableAddonByLocalDir(ctx, "example", "./testdata/example", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
app := v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-example"}, &app)).Should(BeNil())
|
||||
@@ -420,7 +420,7 @@ var _ = Describe("test dry-run addon from local dir", func() {
|
||||
|
||||
h := NewAddonInstaller(ctx, k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, &Registry{Name: LocalAddonRegistryName}, map[string]interface{}{"example": "test-dry-run"}, nil, nil, DryRunAddon)
|
||||
|
||||
err = h.enableAddon(pkg)
|
||||
_, err = h.enableAddon(pkg)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
decoder := yaml3.NewDecoder(h.dryRunBuff)
|
||||
@@ -450,7 +450,7 @@ var _ = Describe("test enable addon which applies the views independently", func
|
||||
|
||||
It("test enable addon which applies the views independently", func() {
|
||||
ctx := context.Background()
|
||||
err := EnableAddonByLocalDir(ctx, "test-view", "./testdata/test-view", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
_, err := EnableAddonByLocalDir(ctx, "test-view", "./testdata/test-view", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
app := v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-test-view"}, &app)).Should(BeNil())
|
||||
@@ -459,6 +459,43 @@ var _ = Describe("test enable addon which applies the views independently", func
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test enable addon with notes", func() {
|
||||
BeforeEach(func() {
|
||||
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-test-notes"}}
|
||||
Expect(k8sClient.Delete(ctx, &app)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
|
||||
sec := v1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-secret-test-notes"}}
|
||||
Expect(k8sClient.Delete(ctx, &sec)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
|
||||
})
|
||||
|
||||
It("test 'enable' addon which render notes output", func() {
|
||||
ctx := context.Background()
|
||||
addonInputArgs := map[string]interface{}{"example": "test"}
|
||||
// inject runtime info
|
||||
addonInputArgs[InstallerRuntimeOption] = map[string]interface{}{
|
||||
"upgrade": false,
|
||||
}
|
||||
notes, err := EnableAddonByLocalDir(ctx, "test-notes", "./testdata/test-notes", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, addonInputArgs)
|
||||
Expect(err).Should(BeNil())
|
||||
app := v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-test-notes"}, &app)).Should(BeNil())
|
||||
Expect(notes).Should(ContainSubstring(`Thank you for your first installation!
|
||||
Please refer to URL.`))
|
||||
})
|
||||
|
||||
It("test 'upgrade' addon which render notes output", func() {
|
||||
ctx := context.Background()
|
||||
addonInputArgs := map[string]interface{}{"example": "test"}
|
||||
// inject runtime info
|
||||
addonInputArgs[InstallerRuntimeOption] = map[string]interface{}{
|
||||
"upgrade": true,
|
||||
}
|
||||
notes, err := EnableAddonByLocalDir(ctx, "test-notes-upgrade", "./testdata/test-notes", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, addonInputArgs)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(notes).Should(ContainSubstring(`Thank you for your upgrade!
|
||||
Please refer to URL.`))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test override defs of addon", func() {
|
||||
It("test compDef exist", func() {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -1057,7 +1057,7 @@ func TestCheckEnableAddonErrorWhenMissMatch(t *testing.T) {
|
||||
version2.VelaVersion = "v1.3.0"
|
||||
i := InstallPackage{Meta: Meta{SystemRequirements: &SystemRequirements{VelaVersion: ">=1.4.0"}}}
|
||||
installer := &Installer{}
|
||||
err := installer.enableAddon(&i)
|
||||
_, err := installer.enableAddon(&i)
|
||||
assert.Equal(t, errors.As(err, &VersionUnMatchError{}), true)
|
||||
}
|
||||
|
||||
@@ -1082,7 +1082,6 @@ func TestPackageAddon(t *testing.T) {
|
||||
archiver, err = PackageAddon(invalidAddonMetadata)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "", archiver)
|
||||
|
||||
}
|
||||
|
||||
func TestGenerateAnnotation(t *testing.T) {
|
||||
|
||||
+11
-20
@@ -52,17 +52,13 @@ const (
|
||||
)
|
||||
|
||||
// EnableAddon will enable addon with dependency check, source is where addon from.
|
||||
func EnableAddon(ctx context.Context, name string, version string, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache, registries []Registry, opts ...InstallOption) error {
|
||||
func EnableAddon(ctx context.Context, name string, version string, cli client.Client, discoveryClient *discovery.DiscoveryClient, apply apply.Applicator, config *rest.Config, r Registry, args map[string]interface{}, cache *Cache, registries []Registry, opts ...InstallOption) (string, error) {
|
||||
h := NewAddonInstaller(ctx, cli, discoveryClient, apply, config, &r, args, cache, registries, opts...)
|
||||
pkg, err := h.loadInstallPackage(name, version)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
err = h.enableAddon(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return h.enableAddon(pkg)
|
||||
}
|
||||
|
||||
// DisableAddon will disable addon from cluster.
|
||||
@@ -91,39 +87,34 @@ func DisableAddon(ctx context.Context, cli client.Client, name string, config *r
|
||||
}
|
||||
|
||||
// EnableAddonByLocalDir enable an addon from local dir
|
||||
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{}, opts ...InstallOption) 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{}, opts ...InstallOption) (string, error) {
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
r := localReader{dir: absDir, name: name}
|
||||
metas, err := r.ListAddonMeta()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
meta := metas[r.name]
|
||||
UIData, err := GetUIDataFromReader(r, &meta, UIMetaOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
pkg, err := GetInstallPackageFromReader(r, &meta, UIData)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
h := NewAddonInstaller(ctx, cli, dc, applicator, config, &Registry{Name: LocalAddonRegistryName}, args, nil, nil, opts...)
|
||||
needEnableAddonNames, err := h.checkDependency(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if len(needEnableAddonNames) > 0 {
|
||||
return fmt.Errorf("you must first enable dependencies: %v", needEnableAddonNames)
|
||||
return "", fmt.Errorf("you must first enable dependencies: %v", needEnableAddonNames)
|
||||
}
|
||||
|
||||
err = h.enableAddon(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return h.enableAddon(pkg)
|
||||
}
|
||||
|
||||
// GetAddonStatus is general func for cli and apiServer get addon status
|
||||
|
||||
+11
-5
@@ -60,8 +60,9 @@ const (
|
||||
)
|
||||
|
||||
type addonCueTemplateRender struct {
|
||||
addon *InstallPackage
|
||||
inputArgs map[string]interface{}
|
||||
addon *InstallPackage
|
||||
inputArgs map[string]interface{}
|
||||
contextInfo map[string]interface{}
|
||||
}
|
||||
|
||||
func (a addonCueTemplateRender) formatContext() (string, error) {
|
||||
@@ -69,6 +70,10 @@ func (a addonCueTemplateRender) formatContext() (string, error) {
|
||||
if args == nil {
|
||||
args = map[string]interface{}{}
|
||||
}
|
||||
contextInfo := a.contextInfo
|
||||
if contextInfo == nil {
|
||||
contextInfo = map[string]interface{}{}
|
||||
}
|
||||
bt, err := json.Marshal(args)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -80,12 +85,13 @@ func (a addonCueTemplateRender) formatContext() (string, error) {
|
||||
// in case the user defined data has packages
|
||||
contextFile.WriteString(a.addon.Parameters + "\n")
|
||||
|
||||
// addon metadata context
|
||||
metadataJSON, err := json.Marshal(a.addon.Meta)
|
||||
// add metadata of addon into context
|
||||
contextInfo["metadata"] = a.addon.Meta
|
||||
contextJSON, err := json.Marshal(contextInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
contextFile.WriteString(fmt.Sprintf("context: metadata: %s\n", string(metadataJSON)))
|
||||
contextFile.WriteString(fmt.Sprintf("context: %s\n", string(contextJSON)))
|
||||
// parameter definition
|
||||
contextFile.WriteString(paramFile + "\n")
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
info: string
|
||||
|
||||
if !context.installer.upgrade {
|
||||
info: "first installation!"
|
||||
}
|
||||
if context.installer.upgrade {
|
||||
info: "upgrade!"
|
||||
}
|
||||
|
||||
notes: "Thank you for your " + """
|
||||
\(info)
|
||||
Please refer to URL.
|
||||
"""
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
name: test-notes
|
||||
version: 1.0.0
|
||||
description: test
|
||||
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||
url: https://terraform.io/
|
||||
|
||||
tags: []
|
||||
|
||||
deployTo:
|
||||
controlPlane: true
|
||||
runtimeCluster: false
|
||||
|
||||
dependencies: []
|
||||
|
||||
invisible: false
|
||||
@@ -66,6 +66,7 @@ type InstallPackage struct {
|
||||
YAMLTemplates []ElementFile `json:"YAMLTemplates,omitempty"`
|
||||
AppTemplate *v1beta1.Application `json:"appTemplate"`
|
||||
AppCueTemplate ElementFile `json:"appCueTemplate,omitempty"`
|
||||
Notes ElementFile `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
// WholeAddonPackage contains all infos of an addon
|
||||
|
||||
@@ -415,7 +415,8 @@ func (u *addonServiceImpl) EnableAddon(ctx context.Context, name string, args ap
|
||||
if len(args.RegistryName) != 0 && args.RegistryName != r.Name {
|
||||
continue
|
||||
}
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
// TODO: response the additional info to velaux users
|
||||
_, err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -486,7 +487,8 @@ func (u *addonServiceImpl) UpdateAddon(ctx context.Context, name string, args ap
|
||||
}
|
||||
|
||||
for i, r := range registries {
|
||||
err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
// TODO: response the additional info to velaux users
|
||||
_, err = pkgaddon.EnableAddon(ctx, name, args.Version, u.kubeClient, u.discoveryClient, u.apply, u.config, r, args.Args, u.addonRegistryCache, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
+45
-30
@@ -150,7 +150,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
vela addon enable <registryName>/<addonName>
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
var additionalInfo string
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify addon name")
|
||||
}
|
||||
@@ -176,6 +176,11 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
}
|
||||
addonOrDir := args[0]
|
||||
var name = addonOrDir
|
||||
// inject runtime info
|
||||
addonArgs[pkgaddon.InstallerRuntimeOption] = map[string]interface{}{
|
||||
"upgrade": false,
|
||||
}
|
||||
|
||||
if file, err := os.Stat(addonOrDir); err == nil {
|
||||
if !file.IsDir() {
|
||||
return fmt.Errorf("%s is not addon dir", addonOrDir)
|
||||
@@ -192,7 +197,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
additionalInfo, err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -205,7 +210,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = enableAddon(ctx, k8sClient, dc, config, name, addonVersion, addonArgs)
|
||||
additionalInfo, err = enableAddon(ctx, k8sClient, dc, config, name, addonVersion, addonArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -214,7 +219,7 @@ func NewAddonEnableCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Com
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Addon %s enabled successfully.\n", name)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, name, false)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, name, additionalInfo, false)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -229,7 +234,7 @@ 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) {
|
||||
func AdditionalEndpointPrinter(ctx context.Context, c common.Args, k8sClient client.Client, name, info string, isUpgrade bool) {
|
||||
err := printAppEndpoints(ctx, addonutil.Addon2AppName(name), types.DefaultKubeVelaNS, Filter{}, c, true)
|
||||
if err != nil {
|
||||
fmt.Println("Get application endpoints error:", err)
|
||||
@@ -247,6 +252,9 @@ func AdditionalEndpointPrinter(ctx context.Context, c common.Args, k8sClient cli
|
||||
fmt.Println()
|
||||
fmt.Println(`Please refer to https://kubevela.io/docs/reference/addons/velaux for more VelaUX addon installation and visiting method.`)
|
||||
}
|
||||
if len(info) > 0 {
|
||||
fmt.Println(info)
|
||||
}
|
||||
}
|
||||
|
||||
// NewAddonUpgradeCommand create addon upgrade command
|
||||
@@ -295,7 +303,13 @@ non-empty new arg
|
||||
addonInputArgs[types.ClustersArg] = clusterArgs
|
||||
}
|
||||
addonOrDir := args[0]
|
||||
var name string
|
||||
|
||||
// inject runtime info
|
||||
addonInputArgs[pkgaddon.InstallerRuntimeOption] = map[string]interface{}{
|
||||
"upgrade": true,
|
||||
}
|
||||
|
||||
var name, additionalInfo string
|
||||
if file, err := os.Stat(addonOrDir); err == nil {
|
||||
if !file.IsDir() {
|
||||
return fmt.Errorf("%s is not addon dir", addonOrDir)
|
||||
@@ -315,7 +329,7 @@ non-empty new arg
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
additionalInfo, err = enableAddonByLocal(ctx, name, addonOrDir, k8sClient, dc, config, addonArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -332,14 +346,14 @@ non-empty new arg
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = enableAddon(ctx, k8sClient, dc, config, addonOrDir, addonVersion, addonArgs)
|
||||
additionalInfo, err = enableAddon(ctx, k8sClient, dc, config, addonOrDir, addonVersion, addonArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Addon %s enabled successfully.", name)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, name, true)
|
||||
fmt.Printf("Addon %s enabled successfully.\n", name)
|
||||
AdditionalEndpointPrinter(ctx, c, k8sClient, name, additionalInfo, true)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -547,16 +561,17 @@ $ HELM_REPO_USERNAME=name HELM_REPO_PASSWORD=pswd vela addon push mongo-1.0.0.tg
|
||||
return cmd
|
||||
}
|
||||
|
||||
func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, name string, version string, args map[string]interface{}) error {
|
||||
func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, name string, version string, args map[string]interface{}) (string, error) {
|
||||
var err error
|
||||
var additionalInfo string
|
||||
registryDS := pkgaddon.NewRegistryDataStore(k8sClient)
|
||||
registries, err := registryDS.ListRegistries(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
registryName, addonName, err := splitSpecifyRegistry(name)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if len(registryName) != 0 {
|
||||
foundRegistry := false
|
||||
@@ -566,7 +581,7 @@ func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.Dis
|
||||
}
|
||||
}
|
||||
if !foundRegistry {
|
||||
return fmt.Errorf("specified registry %s not exist", registryName)
|
||||
return "", fmt.Errorf("specified registry %s not exist", registryName)
|
||||
}
|
||||
}
|
||||
for i, registry := range registries {
|
||||
@@ -574,7 +589,7 @@ func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.Dis
|
||||
if len(registryName) != 0 && registryName != registry.Name {
|
||||
continue
|
||||
}
|
||||
err = pkgaddon.EnableAddon(ctx, addonName, version, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries), opts...)
|
||||
additionalInfo, err = pkgaddon.EnableAddon(ctx, addonName, version, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries), opts...)
|
||||
if errors.Is(err, pkgaddon.ErrNotExist) || errors.Is(err, pkgaddon.ErrFetch) {
|
||||
continue
|
||||
}
|
||||
@@ -582,28 +597,27 @@ func enableAddon(ctx context.Context, k8sClient client.Client, dc *discovery.Dis
|
||||
// Get available version of the addon
|
||||
availableVersion, err := unMatchErr.GetAvailableVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
input := NewUserInput()
|
||||
if input.AskBool(unMatchErr.Error(), &UserInputOptions{AssumeYes: false}) {
|
||||
err = pkgaddon.EnableAddon(ctx, addonName, availableVersion, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
return err
|
||||
return pkgaddon.EnableAddon(ctx, addonName, availableVersion, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, registry, args, nil, pkgaddon.FilterDependencyRegistries(i, registries))
|
||||
}
|
||||
// The user does not agree to use the version provided by us
|
||||
return fmt.Errorf("you can try another version by command: \"vela addon enable %s --version <version> \" ", addonName)
|
||||
return "", fmt.Errorf("you can try another version by command: \"vela addon enable %s --version <version> \" ", addonName)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if err = waitApplicationRunning(k8sClient, addonName); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
return nil
|
||||
return additionalInfo, nil
|
||||
}
|
||||
if len(registryName) != 0 {
|
||||
return fmt.Errorf("addon: %s not found in registry %s", addonName, registryName)
|
||||
return "", fmt.Errorf("addon: %s not found in registry %s", addonName, registryName)
|
||||
}
|
||||
return fmt.Errorf("addon: %s not found in all candidate registries", addonName)
|
||||
return "", fmt.Errorf("addon: %s not found in all candidate registries", addonName)
|
||||
}
|
||||
|
||||
func addonOptions() []pkgaddon.InstallOption {
|
||||
@@ -621,15 +635,16 @@ func addonOptions() []pkgaddon.InstallOption {
|
||||
}
|
||||
|
||||
// enableAddonByLocal enable addon in local dir and return the addon name
|
||||
func enableAddonByLocal(ctx context.Context, name string, dir string, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, args map[string]interface{}) error {
|
||||
func enableAddonByLocal(ctx context.Context, name string, dir string, k8sClient client.Client, dc *discovery.DiscoveryClient, config *rest.Config, args map[string]interface{}) (string, error) {
|
||||
opts := addonOptions()
|
||||
if err := pkgaddon.EnableAddonByLocalDir(ctx, name, dir, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, args, opts...); err != nil {
|
||||
return err
|
||||
info, err := pkgaddon.EnableAddonByLocalDir(ctx, name, dir, k8sClient, dc, apply.NewAPIApplicator(k8sClient), config, args, opts...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := waitApplicationRunning(k8sClient, name); err != nil {
|
||||
return err
|
||||
if err = waitApplicationRunning(k8sClient, name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return nil
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func disableAddon(client client.Client, name string, config *rest.Config, force bool) error {
|
||||
|
||||
Reference in New Issue
Block a user