mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-18 12:06:38 +00:00
support vela addon:install
This commit is contained in:
@@ -44,7 +44,19 @@ type Template struct {
|
||||
AppliesTo []string `json:"appliesTo,omitempty"`
|
||||
|
||||
// Plugin Source
|
||||
Source *Source `json:"source,omitempty"`
|
||||
Source *Source `json:"source,omitempty"`
|
||||
Install *Installation `json:"install,omitempty"`
|
||||
}
|
||||
|
||||
type Chart struct {
|
||||
Repo string `json:"repo"`
|
||||
URl string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type Installation struct {
|
||||
Helm []Chart `json:"helm"`
|
||||
}
|
||||
|
||||
type DefinitionType string
|
||||
|
||||
+3
-7
@@ -94,19 +94,15 @@ func newCommand() *cobra.Command {
|
||||
Schema: scheme,
|
||||
}
|
||||
|
||||
if err := system.InitApplicationDir(); err != nil {
|
||||
fmt.Println("InitApplicationDir err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := system.InitDefinitionDir(); err != nil {
|
||||
fmt.Println("InitDefinitionDir err", err)
|
||||
if err := system.InitDirs(); err != nil {
|
||||
fmt.Println("InitDir err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Getting Start
|
||||
cmd.EnvCommandGroup(cmds, commandArgs, ioStream)
|
||||
// Others
|
||||
cmd.AddonCommandGroup(cmds, ioStream)
|
||||
cmd.AddonCommandGroup(cmds, commandArgs, ioStream)
|
||||
// System
|
||||
cmd.SystemCommandGroup(cmds, commandArgs, ioStream)
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: ingresses.networking.k8s.io
|
||||
annotations:
|
||||
"oam.appengine.info/apiVersion": "networking.k8s.io/v1beta1"
|
||||
"oam.appengine.info/kind": "Ingress"
|
||||
spec:
|
||||
revisionEnabled: true
|
||||
appliesToWorkloads:
|
||||
- core.oam.dev/v1alpha2.ContainerizedWorkload
|
||||
- deployments.apps
|
||||
definitionRef:
|
||||
name: ingresses.networking.k8s.io
|
||||
extension:
|
||||
install:
|
||||
helm:
|
||||
- repo: stable
|
||||
name: nginx-ingress
|
||||
version: 1.41.2
|
||||
template: |
|
||||
#Template: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
spec: {
|
||||
rules: [{
|
||||
host: route.domain
|
||||
http: paths: [{
|
||||
backend: {
|
||||
serviceName: route.service
|
||||
servicePort: route.port
|
||||
}}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
route: {
|
||||
domain: string
|
||||
port: *80 | int
|
||||
service: string
|
||||
}
|
||||
|
||||
+126
-3
@@ -6,8 +6,14 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
|
||||
|
||||
"github.com/gosuri/uitable"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/utils/system"
|
||||
|
||||
@@ -19,11 +25,12 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func AddonCommandGroup(parentCmd *cobra.Command, ioStream cmdutil.IOStreams) {
|
||||
func AddonCommandGroup(parentCmd *cobra.Command, c types.Args, ioStream cmdutil.IOStreams) {
|
||||
parentCmd.AddCommand(
|
||||
NewAddonConfigCommand(ioStream),
|
||||
NewAddonListCommand(ioStream),
|
||||
NewAddonUpdateCommand(ioStream),
|
||||
NewAddonInstallCommand(c, ioStream),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -72,6 +79,37 @@ func NewAddonConfigCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewAddonInstallCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "addon:install <reponame>/<name>",
|
||||
Short: "Install addon plugin into cluster",
|
||||
Long: "Install addon plugin into cluster",
|
||||
Example: `vela addon:install myhub/route`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
argsLength := len(args)
|
||||
if argsLength < 1 {
|
||||
return errors.New("you must specify <reponame>/<name> for addon plugin you want to install")
|
||||
}
|
||||
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss := strings.Split(args[0], "/")
|
||||
if len(ss) < 2 {
|
||||
return errors.New("invalid format for " + args[0] + ", please follow format <reponame>/<name>")
|
||||
}
|
||||
repoName := ss[0]
|
||||
name := ss[1]
|
||||
return InstallAddonPlugin(newClient, repoName, name, ioStreams)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
types.TagCommandType: types.TypeOthers,
|
||||
},
|
||||
}
|
||||
cmd.PersistentFlags().StringP("token", "t", "", "Github Repo token")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewAddonUpdateCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "addon:update <repoName>",
|
||||
@@ -87,6 +125,9 @@ func NewAddonUpdateCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
if len(args) > 0 {
|
||||
specified = args[0]
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
return fmt.Errorf("no addon repo configured")
|
||||
}
|
||||
find := false
|
||||
if specified != "" {
|
||||
for idx, r := range repos {
|
||||
@@ -135,12 +176,17 @@ func NewAddonListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
table := uitable.New()
|
||||
table.AddRow("NAME", "TYPE", "DEFINITION", "STATUS", "APPLIES-TO")
|
||||
if repoName != "" {
|
||||
return ListRepoAddons(table, filepath.Join(dir, repoName), ioStreams)
|
||||
if err = ListRepoAddons(table, filepath.Join(dir, repoName), ioStreams); err != nil {
|
||||
return err
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
dirs, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dd := range dirs {
|
||||
if !dd.IsDir() {
|
||||
continue
|
||||
@@ -149,6 +195,7 @@ func NewAddonListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
@@ -158,6 +205,76 @@ func NewAddonListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func InstallAddonPlugin(client client.Client, repoName, addonName string, ioStreams cmdutil.IOStreams) error {
|
||||
dir, _ := system.GetRepoDir()
|
||||
repoDir := filepath.Join(dir, repoName)
|
||||
tp, err := GetTemplate(repoName, addonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tp.Type {
|
||||
case types.TypeWorkload:
|
||||
var wd v1alpha2.WorkloadDefinition
|
||||
workloadData, err := ioutil.ReadFile(filepath.Join(repoDir, tp.CrdName+".yaml"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if err = yaml.Unmarshal(workloadData, &wd); err != nil {
|
||||
return err
|
||||
}
|
||||
wd.Namespace = types.DefaultOAMNS
|
||||
ioStreams.Info("Installing workload plugin " + wd.Name)
|
||||
if tp.Install != nil {
|
||||
if err = InstallHelmChart(ioStreams, tp.Install.Helm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return client.Create(context.Background(), &wd)
|
||||
case types.TypeTrait:
|
||||
var td v1alpha2.TraitDefinition
|
||||
traitdata, err := ioutil.ReadFile(filepath.Join(repoDir, tp.CrdName+".yaml"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if err = yaml.Unmarshal(traitdata, &td); err != nil {
|
||||
return err
|
||||
}
|
||||
td.Namespace = types.DefaultOAMNS
|
||||
ioStreams.Info("Installing trait plugin " + td.Name)
|
||||
if tp.Install != nil {
|
||||
if err = InstallHelmChart(ioStreams, tp.Install.Helm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return client.Create(context.Background(), &td)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InstallHelmChart(ioStreams cmdutil.IOStreams, charts []types.Chart) error {
|
||||
for _, c := range charts {
|
||||
if err := HelmInstall(ioStreams, c.Repo, c.URl, c.Repo+"/"+c.Name, c.Version, c.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetTemplate(repoName, addonName string) (types.Template, error) {
|
||||
dir, _ := system.GetRepoDir()
|
||||
repoDir := filepath.Join(dir, repoName)
|
||||
templates, err := plugins.LoadPluginsFromLocal(repoDir)
|
||||
if err != nil {
|
||||
return types.Template{}, err
|
||||
}
|
||||
for _, t := range templates {
|
||||
if t.Name == addonName {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return types.Template{}, fmt.Errorf("%s/%s not exist, try vela addon:update %s to sync from remote", repoName, addonName, repoName)
|
||||
}
|
||||
|
||||
func ListRepoAddons(table *uitable.Table, repoDir string, ioStreams cmdutil.IOStreams) error {
|
||||
templates, err := plugins.LoadPluginsFromLocal(repoDir)
|
||||
if err != nil {
|
||||
@@ -171,15 +288,21 @@ func ListRepoAddons(table *uitable.Table, repoDir string, ioStreams cmdutil.IOSt
|
||||
status := CheckInstalled(baseDir, p)
|
||||
table.AddRow(baseDir+"/"+p.Name, p.Type, p.Type, status, p.AppliesTo)
|
||||
}
|
||||
ioStreams.Info(table.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckInstalled(repoName string, tmp types.Template) string {
|
||||
var status = "uninstalled"
|
||||
dir, _ := system.GetDefinitionDir()
|
||||
switch tmp.Type {
|
||||
case types.TypeTrait:
|
||||
dir = filepath.Join(dir, "traits")
|
||||
case types.TypeWorkload:
|
||||
dir = filepath.Join(dir, "workloads")
|
||||
}
|
||||
installed, _ := plugins.LoadTempFromLocal(dir)
|
||||
for _, i := range installed {
|
||||
//TODO handle source on install
|
||||
if i.Source != nil && i.Source.RepoName == repoName && i.Name == tmp.Name && i.CrdName == tmp.CrdName {
|
||||
return "installed"
|
||||
}
|
||||
|
||||
+11
-15
@@ -185,35 +185,35 @@ func (i *initCmd) IsOamRuntimeExist() bool {
|
||||
}
|
||||
|
||||
func InstallOamRuntime(ioStreams cmdutil.IOStreams, version string) error {
|
||||
return HelmInstall(ioStreams, types.DefaultOAMRepoName, types.DefaultOAMRepoUrl, types.DefaultOAMChartName, version, types.DefaultOAMReleaseName)
|
||||
}
|
||||
|
||||
if !IsHelmRepositoryExist(types.DefaultOAMRepoName, types.DefaultOAMRepoUrl) {
|
||||
err := AddHelmRepository(types.DefaultOAMRepoName, types.DefaultOAMRepoUrl,
|
||||
func HelmInstall(ioStreams cmdutil.IOStreams, repoName, repoUrl, chartName, version, releaseName string) error {
|
||||
if !IsHelmRepositoryExist(repoName, repoUrl) {
|
||||
err := AddHelmRepository(repoName, repoUrl,
|
||||
"", "", "", "", "", false, ioStreams.Out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
chartClient, err := NewHelmInstall(version, ioStreams)
|
||||
chartClient, err := NewHelmInstall(version, releaseName, ioStreams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chartRequested, err := GetChart(chartClient, types.DefaultOAMChartName)
|
||||
chartRequested, err := GetChart(chartClient, chartName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
release, err := chartClient.Run(chartRequested, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Successfully installed oam-kubernetes-runtime release: ", release.Name)
|
||||
ioStreams.Infof("Successfully installed %s as release name %s\n", chartName, release.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHelmInstall(version string, ioStreams cmdutil.IOStreams) (*action.Install, error) {
|
||||
func NewHelmInstall(version, releaseName string, ioStreams cmdutil.IOStreams) (*action.Install, error) {
|
||||
actionConfig := new(action.Configuration)
|
||||
|
||||
if err := actionConfig.Init(
|
||||
@@ -227,12 +227,8 @@ func NewHelmInstall(version string, ioStreams cmdutil.IOStreams) (*action.Instal
|
||||
|
||||
client := action.NewInstall(actionConfig)
|
||||
client.Namespace = types.DefaultOAMNS
|
||||
client.ReleaseName = types.DefaultOAMReleaseName
|
||||
if len(version) > 0 {
|
||||
client.Version = version
|
||||
return client, nil
|
||||
}
|
||||
client.Version = types.DefaultOAMVersion
|
||||
client.ReleaseName = releaseName
|
||||
client.Version = version
|
||||
return client, nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+13
-5
@@ -1,11 +1,19 @@
|
||||
#Template: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Route"
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
spec: {
|
||||
domain: route.domain
|
||||
rules: [{
|
||||
host: route.domain
|
||||
http: paths: [{
|
||||
backend: {
|
||||
serviceName: route.service
|
||||
servicePort: route.port
|
||||
}}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
route: {
|
||||
domain: string
|
||||
domain: string
|
||||
port: *80 | int
|
||||
service: string
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/utils/system"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -91,6 +93,7 @@ func HandleTemplate(in *runtime.RawExtension, name, syncDir string) (types.Templ
|
||||
if tmp.Template == "" {
|
||||
return types.Template{}, errors.New("template not exist in definition")
|
||||
}
|
||||
system.StatAndCreate(syncDir)
|
||||
filePath := filepath.Join(syncDir, name+".cue")
|
||||
err = ioutil.WriteFile(filePath, []byte(tmp.Template), 0644)
|
||||
if err != nil {
|
||||
|
||||
@@ -66,7 +66,7 @@ func LoadPluginsFromLocal(dir string) ([]types.Template, error) {
|
||||
fmt.Printf("read file %s err %v\n", f.Name(), err)
|
||||
continue
|
||||
}
|
||||
tmp, err := GetDefinitionFromURL(data, filepath.Join(dir, ".tmp"))
|
||||
tmp, err := ParseAndSyncDefinition(data, filepath.Join(dir, ".tmp"))
|
||||
if err != nil {
|
||||
fmt.Printf("get definition of %s err %v\n", f.Name(), err)
|
||||
continue
|
||||
|
||||
@@ -159,7 +159,7 @@ func StoreRepos(repos []RepoConfig) error {
|
||||
return ioutil.WriteFile(config, data, 0644)
|
||||
}
|
||||
|
||||
func GetDefinitionFromURL(data []byte, syncDir string) (types.Template, error) {
|
||||
func ParseAndSyncDefinition(data []byte, syncDir string) (types.Template, error) {
|
||||
var obj = unstructured.Unstructured{Object: make(map[string]interface{})}
|
||||
err := yaml.Unmarshal(data, &obj.Object)
|
||||
if err != nil {
|
||||
@@ -235,9 +235,14 @@ func (g *GithubAddon) SyncRemoteAddons() error {
|
||||
return fmt.Errorf("decode github content %s err %v", *fileContent.Path, err)
|
||||
}
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(repoDir, *fileContent.Name), data, 0644)
|
||||
tmp, err := ParseAndSyncDefinition(data, filepath.Join(dir, ".tmp"))
|
||||
if err != nil {
|
||||
fmt.Printf("write definition %s to %s err %v\n", *fileContent.Name, repoDir, err)
|
||||
fmt.Printf("parse definition of %s err %v\n", *fileContent.Name, err)
|
||||
continue
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(repoDir, tmp.CrdName+".yaml"), data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("write definition %s to %s err %v\n", tmp.CrdName+".yaml", repoDir, err)
|
||||
continue
|
||||
}
|
||||
success++
|
||||
|
||||
@@ -28,7 +28,7 @@ func GetRepoDir() (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, ".repo"), nil
|
||||
return filepath.Join(home, "repositories"), nil
|
||||
}
|
||||
|
||||
func GetRepoConfig() (string, error) {
|
||||
@@ -36,7 +36,6 @@ func GetRepoConfig() (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
StatAndCreate(home)
|
||||
return filepath.Join(home, "config.yaml"), nil
|
||||
}
|
||||
|
||||
@@ -72,12 +71,33 @@ func GetCurrentEnvPath() (string, error) {
|
||||
return filepath.Join(homedir, "curenv"), nil
|
||||
}
|
||||
|
||||
func InitDirs() error {
|
||||
if err := InitDefinitionDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := InitApplicationDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := InitRepositoryDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitRepositoryDir() error {
|
||||
home, err := GetRepoDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return StatAndCreate(filepath.Join(home, ".tmp"))
|
||||
}
|
||||
|
||||
func InitDefinitionDir() error {
|
||||
dir, err := GetDefinitionDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(dir, 0755)
|
||||
return StatAndCreate(dir)
|
||||
}
|
||||
|
||||
func InitApplicationDir() error {
|
||||
@@ -85,7 +105,7 @@ func InitApplicationDir() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(dir, 0755)
|
||||
return StatAndCreate(dir)
|
||||
}
|
||||
|
||||
func InitDefaultEnv() error {
|
||||
@@ -108,8 +128,9 @@ func InitDefaultEnv() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func StatAndCreate(dir string) {
|
||||
func StatAndCreate(dir string) error {
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
return os.MkdirAll(dir, 0755)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user