Skip to content

Commit 8ea8cbf

Browse files
authored
Feat add plugins (#16)
* feat(plugin): expose plugin into command line * feat(connect): allow customized port
1 parent 9b99d88 commit 8ea8cbf

File tree

7 files changed

+182
-27
lines changed

7 files changed

+182
-27
lines changed

cmd/multikf/cmd_connect.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@ func NewConnectCommand(logger log.Logger, ioStreams genericclioptions.IOStreams)
1818
}
1919

2020
func newConnectKubeflowCommand(logger log.Logger, ioStreams genericclioptions.IOStreams) *cobra.Command {
21+
var (
22+
port int // dedicated port
23+
)
2124
handle := func(machineName string) error {
2225
m, err := findMachineByName(machineName, logger)
2326
if err != nil {
2427
return err
2528
}
26-
destPort, err := machine.FindFreePort()
27-
if err != nil {
28-
return err
29+
destPort := port
30+
if !(destPort > 1024 && destPort < 65536) {
31+
logger.V(0).Infof("invaid customized port, use random\n")
32+
destPort, err = machine.FindFreePort()
33+
if err != nil {
34+
return err
35+
}
2936
}
3037
logger.V(0).Infof("now you can open http://localhost:%d\n", destPort)
3138
return m.GetKubeCli().Portforward(m.GetKubeConfig(), "svc/istio-ingressgateway", "istio-system", 80, destPort)
@@ -37,5 +44,7 @@ func newConnectKubeflowCommand(logger log.Logger, ioStreams genericclioptions.IO
3744
return handle(args[0])
3845
},
3946
}
47+
48+
cmd.Flags().IntVar(&port, "port", 0, "customized port number for connect, ranged should be 65535> >1024, default is 0 (random)")
4049
return cmd
4150
}

cmd/multikf/cmd_plugins.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package multikf
2+
3+
import (
4+
"github.com/footprintai/multikf/pkg/machine/plugins"
5+
"github.com/spf13/cobra"
6+
"k8s.io/cli-runtime/pkg/genericclioptions"
7+
"sigs.k8s.io/kind/pkg/log"
8+
)
9+
10+
func NewPluginCommand(logger log.Logger, ioStreams genericclioptions.IOStreams) *cobra.Command {
11+
cmd := &cobra.Command{
12+
Use: "plugin",
13+
Short: "plugin",
14+
Long: `enable plugins to the underlying k8s`,
15+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
16+
},
17+
}
18+
cmd.AddCommand(newAddPluginCommand(logger, ioStreams))
19+
cmd.AddCommand(newRemovePluginCommand(logger, ioStreams))
20+
return cmd
21+
}
22+
23+
func newAddPluginCommand(logger log.Logger, ioStreams genericclioptions.IOStreams) *cobra.Command {
24+
var (
25+
withKubeflow bool // install with kubeflow components
26+
withKubeflowVersion string // with kubeflow version
27+
withKubeflowDefaultPassword string // with kubeflow defaultpassword
28+
)
29+
30+
handle := func(machineName string) error {
31+
m, err := findMachineByName(machineName, logger)
32+
if err != nil {
33+
return err
34+
}
35+
var installedPlugins []plugins.Plugin
36+
if withKubeflow {
37+
installedPlugins = append(installedPlugins,
38+
kubeflowPlugin{
39+
withKubeflowDefaultPassword: withKubeflowDefaultPassword,
40+
kubeflowVersion: plugins.NewTypePluginVersion(withKubeflowVersion),
41+
},
42+
)
43+
}
44+
return plugins.AddPlugins(m, installedPlugins...)
45+
}
46+
cmd := &cobra.Command{
47+
Use: "add <machine-name> --with_kubeflow",
48+
Short: "add kubeflow plugins to the machine",
49+
RunE: func(cmd *cobra.Command, args []string) error {
50+
return handle(args[0])
51+
},
52+
}
53+
54+
cmd.Flags().BoolVar(&withKubeflow, "with_kubeflow", true, "install kubeflow modules (default: true)")
55+
cmd.Flags().StringVar(&withKubeflowVersion, "kubeflow_version", "v1.4", "kubeflow version v1.4/v1.5.1")
56+
cmd.Flags().StringVar(&withKubeflowDefaultPassword, "with_password", "12341234", "with a specific password for default user (default: 12341234)")
57+
58+
return cmd
59+
}
60+
61+
func newRemovePluginCommand(logger log.Logger, ioStreams genericclioptions.IOStreams) *cobra.Command {
62+
var (
63+
removeKubeflow bool // remove kubeflow components
64+
removeKubeflowVersion string // with kubeflow version
65+
)
66+
67+
handle := func(machineName string) error {
68+
m, err := findMachineByName(machineName, logger)
69+
if err != nil {
70+
return err
71+
}
72+
var removingPlugins []plugins.Plugin
73+
if removeKubeflow {
74+
removingPlugins = append(removingPlugins, kubeflowPlugin{kubeflowVersion: plugins.NewTypePluginVersion(removeKubeflowVersion)})
75+
}
76+
return plugins.RemovePlugins(m, removingPlugins...)
77+
}
78+
cmd := &cobra.Command{
79+
Use: "remove <machine-name> --remove_kubeflow",
80+
Short: "rmeove kubeflow plugins to the machine",
81+
RunE: func(cmd *cobra.Command, args []string) error {
82+
return handle(args[0])
83+
},
84+
}
85+
86+
cmd.Flags().BoolVar(&removeKubeflow, "remove_kubeflow", false, "remove kubeflow modules (default: false)")
87+
cmd.Flags().StringVar(&removeKubeflowVersion, "kubeflow_version", "v1.4", "kubeflow version v1.4/v1.5.1")
88+
return cmd
89+
}

cmd/multikf/root.go

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func NewRootCommand(logger log.Logger, ioStreams genericclioptions.IOStreams) *c
3333
cmd.AddCommand(NewListCommand(logger, ioStreams))
3434
cmd.AddCommand(NewDeleteCommand(logger, ioStreams))
3535
cmd.AddCommand(NewConnectCommand(logger, ioStreams))
36+
cmd.AddCommand(NewPluginCommand(logger, ioStreams))
3637

3738
cmd.PersistentFlags().StringVar(&guestRootDir, "dir", ".multikfdir", "multikf root dir")
3839
cmd.PersistentFlags().BoolVar(&verbose, "verbose", true, "verbose (default: true)")

pkg/machine/kubectl/cli.go

+14
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,20 @@ func (cli *CLI) InstallKubeflow(kubeConfigFile string, kfmanifestFile string) er
181181
return nil
182182
}
183183

184+
func (cli *CLI) RemoveKubeflow(kubeConfigFile string, kfmanifestFile string) error {
185+
cmdAndArgs := []string{
186+
cli.localKubectlBinaryPath,
187+
"delete",
188+
"-f",
189+
kfmanifestFile,
190+
"--kubeconfig",
191+
kubeConfigFile,
192+
}
193+
sr, _, err := cli.runCmd(cmdAndArgs)
194+
ioutil.StderrOnError(sr)
195+
return err
196+
}
197+
184198
func (cli *CLI) PatchKubeflow(kubeConfigFile string) error {
185199
multiCmdAndArgs := [][]string{
186200
[]string{

pkg/machine/plugins/kubeflow/kubeflow_template.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
"golang.org/x/crypto/bcrypt"
1111
)
1212

13-
func NewKubeflow14Template() *KubeflowFileTemplate {
13+
func NewKubeflow14Template() pkgtemplate.TemplateExecutor {
1414
return newKubeflowTemplateWithTemplate("kubeflow-manifest-v1.4.1.yaml", kfmanifests.KF14TemplateString)
1515
}
1616

17-
func NewKubeflow15Template() *KubeflowFileTemplate {
17+
func NewKubeflow15Template() pkgtemplate.TemplateExecutor {
1818
return newKubeflowTemplateWithTemplate("kubeflow-manifest-v1.5.1.yaml", kfmanifests.KF15TemplateString)
1919
}
2020

pkg/machine/plugins/plugins.go

+63-22
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/footprintai/multikf/pkg/machine"
88
kubeflowplugin "github.com/footprintai/multikf/pkg/machine/plugins/kubeflow"
9+
"github.com/footprintai/multikf/pkg/template"
910
templatefs "github.com/footprintai/multikf/pkg/template/fs"
1011
)
1112

@@ -21,21 +22,26 @@ func (t TypePluginVersion) String() string {
2122
return string(t)
2223
}
2324

24-
type kubeflowTemplateMakerFunc func() *kubeflowplugin.KubeflowFileTemplate
25+
var (
26+
TypePluginVersionKF14 = NewTypePluginVersion("v1.4")
27+
TypePluginVersionKF151 = NewTypePluginVersion("v1.5.1")
28+
)
29+
30+
type templateMakerFunc func() template.TemplateExecutor
2531

2632
var (
2733
noVersion = NewTypePluginVersion("v0.0.0")
28-
availableVersions = map[TypePluginVersion]kubeflowTemplateMakerFunc{
29-
NewTypePluginVersion("v1.4"): kubeflowplugin.NewKubeflow14Template,
30-
NewTypePluginVersion("v1.5.1"): kubeflowplugin.NewKubeflow15Template,
34+
availableVersions = map[TypePluginVersion]templateMakerFunc{
35+
TypePluginVersionKF14: kubeflowplugin.NewKubeflow14Template,
36+
TypePluginVersionKF151: kubeflowplugin.NewKubeflow15Template,
3137
}
3238
)
3339

3440
func NewTypePluginVersion(s string) TypePluginVersion {
3541
return TypePluginVersion(s)
3642
}
3743

38-
func KubeflowPluginVersionTemplate(s TypePluginVersion) (TypePluginVersion, *kubeflowplugin.KubeflowFileTemplate) {
44+
func KubeflowPluginVersionTemplate(s TypePluginVersion) (TypePluginVersion, template.TemplateExecutor) {
3945
templateMaker, hasVersion := availableVersions[s]
4046
if !hasVersion {
4147
return noVersion, nil
@@ -48,35 +54,60 @@ type Plugin interface {
4854
PluginVersion() TypePluginVersion
4955
}
5056

51-
func AddPlugins(m machine.MachineCURD, plugins ...Plugin) error {
52-
pluginAndFiles := map[TypePlugin]string{}
57+
type TypeHostFilePath string
58+
59+
func (t TypeHostFilePath) String() string {
60+
return string(t)
61+
}
5362

54-
memFs := templatefs.NewMemoryFilesFs()
63+
func NewTypeHostFilePath(s string) TypeHostFilePath {
64+
return TypeHostFilePath(s)
65+
}
66+
67+
func generatePluginsManifestsMapping(m machine.MachineCURD, dumpToFile bool, plugins ...Plugin) (map[Plugin]template.TemplateExecutor, error) {
68+
pluginAndTmpls := map[Plugin]template.TemplateExecutor{}
5569
for _, plugin := range plugins {
5670
switch plugin.PluginType() {
5771
case TypePluginKubeflow:
5872
// handle kubeflow plugins
5973
_, tmpl := KubeflowPluginVersionTemplate(plugin.PluginVersion())
6074
if tmpl == nil {
61-
return errors.New("plugins: no version found")
62-
}
63-
if err := memFs.Generate(plugin, tmpl); err != nil {
64-
return err
75+
return nil, errors.New("plugins: no version found")
6576
}
66-
pluginAndFiles[plugin.PluginType()] = tmpl.Filename()
77+
pluginAndTmpls[plugin] = tmpl
6778
default:
68-
return errors.New("plugins: no available plugins")
79+
return nil, errors.New("plugins: no available plugins")
6980
}
7081
}
71-
if err := templatefs.NewFolder(m.HostDir()).DumpFiles(true, memFs.FS()); err != nil {
72-
return err
82+
if dumpToFile {
83+
memFs := templatefs.NewMemoryFilesFs()
84+
for plugin, tmpl := range pluginAndTmpls {
85+
if err := memFs.Generate(plugin, tmpl); err != nil {
86+
return nil, err
87+
}
88+
}
89+
// TODO: check whether we want to overwrite exsiting or not
90+
if err := templatefs.NewFolder(m.HostDir()).DumpFiles(true, memFs.FS()); err != nil {
91+
return nil, err
92+
}
7393
}
94+
return pluginAndTmpls, nil
95+
}
96+
97+
func AddPlugins(m machine.MachineCURD, plugins ...Plugin) error {
7498
var err error
75-
_, hasKf := pluginAndFiles[TypePluginKubeflow]
76-
if hasKf {
77-
err = m.GetKubeCli().InstallKubeflow(m.GetKubeConfig(), filepath.Join(m.HostDir(), pluginAndFiles[TypePluginKubeflow]))
78-
if err == nil {
79-
err = m.GetKubeCli().PatchKubeflow(m.GetKubeConfig())
99+
pluginAndTmpls, err := generatePluginsManifestsMapping(m, true, plugins...)
100+
if err != nil {
101+
return nil
102+
}
103+
for plugin, tmpl := range pluginAndTmpls {
104+
if plugin.PluginType() == TypePluginKubeflow {
105+
err = m.GetKubeCli().InstallKubeflow(m.GetKubeConfig(), filepath.Join(m.HostDir(), tmpl.Filename()))
106+
if err == nil {
107+
if plugin.PluginVersion() == TypePluginVersionKF14 {
108+
err = m.GetKubeCli().PatchKubeflow(m.GetKubeConfig())
109+
}
110+
}
80111
}
81112
}
82113
if err != nil {
@@ -86,6 +117,16 @@ func AddPlugins(m machine.MachineCURD, plugins ...Plugin) error {
86117
}
87118

88119
func RemovePlugins(m machine.MachineCURD, plugins ...Plugin) error {
89-
return errors.New("plugins: not imp")
120+
var err error
121+
pluginAndTmpls, err := generatePluginsManifestsMapping(m, false, plugins...)
122+
if err != nil {
123+
return err
124+
}
125+
for plugin, tmpl := range pluginAndTmpls {
126+
if plugin.PluginType() == TypePluginKubeflow {
127+
err = m.GetKubeCli().RemoveKubeflow(m.GetKubeConfig(), filepath.Join(m.HostDir(), tmpl.Filename()))
128+
}
129+
}
130+
return err
90131

91132
}

pkg/template/fs/memfs.go

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io/fs"
66

77
"github.com/footprintai/multikf/pkg/template"
8+
89
//log "github.com/golang/glog"
910
"github.com/spf13/afero"
1011
)

0 commit comments

Comments
 (0)