Skip to content

Commit cbea3f6

Browse files
authored
Merge pull request #3437 from Eileen-Yu/external-plugin-path
✨ Make external plugin path configurable
2 parents d9c14df + 235d1e1 commit cbea3f6

File tree

4 files changed

+200
-27
lines changed

4 files changed

+200
-27
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
require (
1919
github.com/go-logr/logr v1.2.4 // indirect
2020
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
21+
github.com/golang/protobuf v1.5.3 // indirect
2122
github.com/google/go-cmp v0.5.9 // indirect
2223
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
2324
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -26,6 +27,7 @@ require (
2627
golang.org/x/mod v0.10.0 // indirect
2728
golang.org/x/net v0.10.0 // indirect
2829
golang.org/x/sys v0.8.0 // indirect
30+
google.golang.org/protobuf v1.28.0 // indirect
2931
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
3032
gopkg.in/yaml.v2 v2.4.0 // indirect
3133
gopkg.in/yaml.v3 v3.0.1 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
9191
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
9292
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
9393
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
94+
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
9495
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
96+
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
9597
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
9698
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
9799
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -103,6 +105,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
103105
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
104106
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
105107
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
108+
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
106109
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
107110
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
108111
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -471,7 +474,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
471474
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
472475
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
473476
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
477+
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
478+
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
474479
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
480+
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
475481
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
476482
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
477483
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=

pkg/cli/options.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,29 @@ func isHostSupported(host string) bool {
181181
return false
182182
}
183183

184-
// getPluginsRoot detects the host system and gets the plugins root based on the host.
184+
// getPluginsRoot gets the plugin root path.
185185
func getPluginsRoot(host string) (pluginsRoot string, err error) {
186186
if !isHostSupported(host) {
187187
// freebsd, openbsd, windows...
188188
return "", fmt.Errorf("host not supported: %v", host)
189189
}
190190

191+
// if user provides specific path, return
192+
if pluginsPath := os.Getenv("EXTERNAL_PLUGINS_PATH"); pluginsPath != "" {
193+
// verify if the path actually exists
194+
if _, err := os.Stat(pluginsPath); err != nil {
195+
if os.IsNotExist(err) {
196+
// the path does not exist
197+
return "", fmt.Errorf("the specified path %s does not exist", pluginsPath)
198+
}
199+
// some other error
200+
return "", fmt.Errorf("error checking the path: %v", err)
201+
}
202+
// the path exists
203+
return pluginsPath, nil
204+
}
205+
206+
// if no specific path, detects the host system and gets the plugins root based on the host.
191207
pluginsRelativePath := filepath.Join("kubebuilder", "plugins")
192208
if xdgHome := os.Getenv("XDG_CONFIG_HOME"); xdgHome != "" {
193209
return filepath.Join(xdgHome, pluginsRelativePath), nil
@@ -206,9 +222,8 @@ func getPluginsRoot(host string) (pluginsRoot string, err error) {
206222
if err != nil {
207223
return "", fmt.Errorf("error retrieving home dir: %v", err)
208224
}
209-
pluginsRoot = filepath.Join(userHomeDir, pluginsRoot)
210225

211-
return
226+
return filepath.Join(userHomeDir, pluginsRoot), nil
212227
}
213228

214229
// DiscoverExternalPlugins discovers the external plugins in the plugins root directory

pkg/cli/options_test.go

Lines changed: 174 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cli
1818

1919
import (
2020
"errors"
21+
"fmt"
2122
"os"
2223
"path/filepath"
2324
"runtime"
@@ -34,6 +35,179 @@ import (
3435
)
3536

3637
var _ = Describe("Discover external plugins", func() {
38+
Context("with valid plugins root path", func() {
39+
var (
40+
homePath string = os.Getenv("HOME")
41+
customPath string = "/tmp/myplugins"
42+
// store user's original EXTERNAL_PLUGINS_PATH
43+
originalPluginPath string
44+
xdghome string
45+
// store user's original XDG_CONFIG_HOME
46+
originalXdghome string
47+
)
48+
49+
When("XDG_CONFIG_HOME is not set and using the $HOME environment variable", func() {
50+
// store and unset the XDG_CONFIG_HOME
51+
BeforeEach(func() {
52+
originalXdghome = os.Getenv("XDG_CONFIG_HOME")
53+
err := os.Unsetenv("XDG_CONFIG_HOME")
54+
Expect(err).To(BeNil())
55+
})
56+
57+
AfterEach(func() {
58+
if originalXdghome != "" {
59+
// restore the original value
60+
err := os.Setenv("XDG_CONFIG_HOME", originalXdghome)
61+
Expect(err).To(BeNil())
62+
}
63+
})
64+
65+
It("should return the correct path for the darwin OS", func() {
66+
plgPath, err := getPluginsRoot("darwin")
67+
Expect(err).To(BeNil())
68+
Expect(plgPath).To(Equal(fmt.Sprintf("%s/Library/Application Support/kubebuilder/plugins", homePath)))
69+
})
70+
71+
It("should return the correct path for the linux OS", func() {
72+
plgPath, err := getPluginsRoot("linux")
73+
Expect(err).To(BeNil())
74+
Expect(plgPath).To(Equal(fmt.Sprintf("%s/.config/kubebuilder/plugins", homePath)))
75+
})
76+
77+
It("should return error when the host is not darwin / linux", func() {
78+
plgPath, err := getPluginsRoot("random")
79+
Expect(plgPath).To(Equal(""))
80+
Expect(err).ToNot(BeNil())
81+
Expect(err.Error()).To(ContainSubstring("host not supported"))
82+
})
83+
})
84+
85+
When("XDG_CONFIG_HOME is set", func() {
86+
BeforeEach(func() {
87+
// store and set the XDG_CONFIG_HOME
88+
originalXdghome = os.Getenv("XDG_CONFIG_HOME")
89+
err := os.Setenv("XDG_CONFIG_HOME", fmt.Sprintf("%s/.config", homePath))
90+
Expect(err).To(BeNil())
91+
92+
xdghome = os.Getenv("XDG_CONFIG_HOME")
93+
})
94+
95+
AfterEach(func() {
96+
if originalXdghome != "" {
97+
// restore the original value
98+
err := os.Setenv("XDG_CONFIG_HOME", originalXdghome)
99+
Expect(err).To(BeNil())
100+
} else {
101+
// unset if it was originally unset
102+
err := os.Unsetenv("XDG_CONFIG_HOME")
103+
Expect(err).To(BeNil())
104+
}
105+
})
106+
107+
It("should return the correct path for the darwin OS", func() {
108+
plgPath, err := getPluginsRoot("darwin")
109+
Expect(err).To(BeNil())
110+
Expect(plgPath).To(Equal(fmt.Sprintf("%s/kubebuilder/plugins", xdghome)))
111+
})
112+
113+
It("should return the correct path for the linux OS", func() {
114+
plgPath, err := getPluginsRoot("linux")
115+
Expect(err).To(BeNil())
116+
Expect(plgPath).To(Equal(fmt.Sprintf("%s/kubebuilder/plugins", xdghome)))
117+
})
118+
119+
It("should return error when the host is not darwin / linux", func() {
120+
plgPath, err := getPluginsRoot("random")
121+
Expect(plgPath).To(Equal(""))
122+
Expect(err).ToNot(BeNil())
123+
Expect(err.Error()).To(ContainSubstring("host not supported"))
124+
})
125+
})
126+
127+
When("using the custom path", func() {
128+
BeforeEach(func() {
129+
err := os.MkdirAll(customPath, 0750)
130+
Expect(err).To(BeNil())
131+
132+
// store and set the EXTERNAL_PLUGINS_PATH
133+
originalPluginPath = os.Getenv("EXTERNAL_PLUGINS_PATH")
134+
err = os.Setenv("EXTERNAL_PLUGINS_PATH", customPath)
135+
Expect(err).To(BeNil())
136+
})
137+
138+
AfterEach(func() {
139+
if originalPluginPath != "" {
140+
// restore the original value
141+
err := os.Setenv("EXTERNAL_PLUGINS_PATH", originalPluginPath)
142+
Expect(err).To(BeNil())
143+
} else {
144+
// unset if it was originally unset
145+
err := os.Unsetenv("EXTERNAL_PLUGINS_PATH")
146+
Expect(err).To(BeNil())
147+
}
148+
})
149+
150+
It("should return the user given path for darwin OS", func() {
151+
plgPath, err := getPluginsRoot("darwin")
152+
Expect(plgPath).To(Equal(customPath))
153+
Expect(err).To(BeNil())
154+
})
155+
156+
It("should return the user given path for linux OS", func() {
157+
plgPath, err := getPluginsRoot("linux")
158+
Expect(plgPath).To(Equal(customPath))
159+
Expect(err).To(BeNil())
160+
})
161+
162+
It("should report error when the host is not darwin / linux", func() {
163+
plgPath, err := getPluginsRoot("random")
164+
Expect(plgPath).To(Equal(""))
165+
Expect(err).ToNot(BeNil())
166+
Expect(err.Error()).To(ContainSubstring("host not supported"))
167+
})
168+
})
169+
})
170+
171+
Context("with invalid plugins root path", func() {
172+
var originalPluginPath string
173+
174+
BeforeEach(func() {
175+
originalPluginPath = os.Getenv("EXTERNAL_PLUGINS_PATH")
176+
err := os.Setenv("EXTERNAL_PLUGINS_PATH", "/non/existent/path")
177+
Expect(err).To(BeNil())
178+
})
179+
180+
AfterEach(func() {
181+
if originalPluginPath != "" {
182+
// restore the original value
183+
err := os.Setenv("EXTERNAL_PLUGINS_PATH", originalPluginPath)
184+
Expect(err).To(BeNil())
185+
} else {
186+
// unset if it was originally unset
187+
err := os.Unsetenv("EXTERNAL_PLUGINS_PATH")
188+
Expect(err).To(BeNil())
189+
}
190+
})
191+
192+
It("should return an error for the darwin OS", func() {
193+
plgPath, err := getPluginsRoot("darwin")
194+
Expect(err).ToNot(BeNil())
195+
Expect(plgPath).To(Equal(""))
196+
})
197+
198+
It("should return an error for the linux OS", func() {
199+
plgPath, err := getPluginsRoot("linux")
200+
Expect(err).ToNot(BeNil())
201+
Expect(plgPath).To(Equal(""))
202+
})
203+
204+
It("should return an error when the host is not darwin / linux", func() {
205+
plgPath, err := getPluginsRoot("random")
206+
Expect(err).ToNot(BeNil())
207+
Expect(plgPath).To(Equal(""))
208+
})
209+
})
210+
37211
Context("when plugin executables exist in the expected plugin directories", func() {
38212
const (
39213
filePermissions os.FileMode = 755
@@ -219,18 +393,6 @@ var _ = Describe("Discover external plugins", func() {
219393
Expect(err).To(Equal(errPluginsRoot))
220394
})
221395

222-
It("should fail for any other host that is not supported", func() {
223-
_, err := getPluginsRoot("darwin")
224-
Expect(err).To(BeNil())
225-
226-
_, err = getPluginsRoot("linux")
227-
Expect(err).To(BeNil())
228-
229-
_, err = getPluginsRoot("random")
230-
Expect(err).ToNot(BeNil())
231-
Expect(err.Error()).To(ContainSubstring("host not supported"))
232-
})
233-
234396
It("should skip parsing of directories if plugins root is not a directory", func() {
235397
retrievePluginsRoot = func(host string) (string, error) {
236398
return "externalplugin.sh", nil
@@ -240,18 +402,6 @@ var _ = Describe("Discover external plugins", func() {
240402
Expect(err).To(BeNil())
241403
})
242404

243-
It("should fail for any other host that is not supported", func() {
244-
_, err := getPluginsRoot("darwin")
245-
Expect(err).To(BeNil())
246-
247-
_, err = getPluginsRoot("linux")
248-
Expect(err).To(BeNil())
249-
250-
_, err = getPluginsRoot("random")
251-
Expect(err).ToNot(BeNil())
252-
Expect(err.Error()).To(ContainSubstring("host not supported"))
253-
})
254-
255405
It("should return full path to the external plugins without XDG_CONFIG_HOME", func() {
256406
if _, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok {
257407
err = os.Setenv("XDG_CONFIG_HOME", "")

0 commit comments

Comments
 (0)