support vela addon:install

This commit is contained in:
天元
2020-08-12 13:31:31 +08:00
parent ae4ae3fff6
commit 2f94c17890
10 changed files with 246 additions and 41 deletions
+13 -1
View File
@@ -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
View File
@@ -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)
+41
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+13 -5
View File
@@ -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
}
+3
View File
@@ -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 {
+1 -1
View File
@@ -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
+8 -3
View File
@@ -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++
+27 -6
View File
@@ -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
}