Skip to content

Commit f55fea1

Browse files
committed
separate subcommands into separate files
Signed-off-by: Bryce Palmer <[email protected]>
1 parent 92ccb4f commit f55fea1

File tree

7 files changed

+285
-225
lines changed

7 files changed

+285
-225
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/pflag"
7+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/external"
8+
)
9+
10+
// apiCmd handles all the logic for the `create api` subcommand of this sample external plugin
11+
func apiCmd(pr *external.PluginRequest) external.PluginResponse {
12+
pluginResponse := external.PluginResponse{
13+
APIVersion: "v1alpha1",
14+
Command: "create api",
15+
Universe: pr.Universe,
16+
}
17+
18+
// Here is an example of parsing a flag from a Kubebuilder external plugin request
19+
flags := pflag.NewFlagSet("apiFlags", pflag.ContinueOnError)
20+
flags.Int("number", 1, "set a number to be added in the scaffolded apiFile.txt")
21+
flags.Parse(pr.Args)
22+
number, _ := flags.GetInt("number")
23+
24+
// Phase 2 Plugins uses the concept of a "universe" to represent the filesystem for a plugin.
25+
// This universe is a key:value mapping of filename:contents. Here we are adding the file
26+
// "apiFile.txt" to the universe with some content. When this is returned Kubebuilder will
27+
// take all values within the "universe" and write them to the user's filesystem.
28+
pluginResponse.Universe["apiFile.txt"] = fmt.Sprintf("A simple text file created with the `create api` subcommand\nNUMBER: %d", number)
29+
30+
return pluginResponse
31+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package main
2+
3+
import (
4+
"github.com/spf13/pflag"
5+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/external"
6+
)
7+
8+
// flagsCmd handles all the logic for the `flags` subcommand of the sample external plugin.
9+
// In Kubebuilder's Phase 2 Plugins the `flags` subcommand is an optional subcommand for
10+
// external plugins to support. The `flags` subcommand allows for an external plugin
11+
// to provide Kubebuilder with a list of flags that the `init`, `create api`, `create webhook`,
12+
// and `edit` subcommands allow. This allows Kubebuilder to give an external plugin the ability
13+
// to feel like a native Kubebuilder plugin to a Kubebuilder user by only binding the supported
14+
// flags and failing early if an unknown flag is provided.
15+
func flagsCmd(pr *external.PluginRequest) external.PluginResponse {
16+
pluginResponse := external.PluginResponse{
17+
APIVersion: "v1alpha1",
18+
Command: "flags",
19+
Universe: pr.Universe,
20+
Flags: []external.Flag{},
21+
}
22+
23+
// Here is an example of parsing multiple flags from a Kubebuilder external plugin request
24+
flagsToParse := pflag.NewFlagSet("flagsFlags", pflag.ContinueOnError)
25+
flagsToParse.Bool("init", false, "sets the init flag to true")
26+
flagsToParse.Bool("api", false, "sets the api flag to true")
27+
flagsToParse.Bool("webhook", false, "sets the webhook flag to true")
28+
29+
flagsToParse.Parse(pr.Args)
30+
31+
initFlag, _ := flagsToParse.GetBool("init")
32+
apiFlag, _ := flagsToParse.GetBool("api")
33+
webhookFlag, _ := flagsToParse.GetBool("webhook")
34+
35+
// The Phase 2 Plugins implementation will only ever pass a single boolean flag
36+
// argument in the JSON request `args` field. The flag will be `--init` if it is
37+
// attempting to get the flags for the `init` subcommand, `--api` for `create api`,
38+
// `--webhook` for `create webhook`, and `--edit` for `edit`
39+
if initFlag {
40+
// Add a flag to the JSON response `flags` field that Kubebuilder reads
41+
// to ensure it binds to the flags given in the response.
42+
pluginResponse.Flags = append(pluginResponse.Flags, external.Flag{
43+
Name: "domain",
44+
Type: "string",
45+
Default: "example.domain.com",
46+
Usage: "sets the domain added in the scaffolded initFile.txt",
47+
})
48+
} else if apiFlag {
49+
pluginResponse.Flags = append(pluginResponse.Flags, external.Flag{
50+
Name: "number",
51+
Type: "int",
52+
Default: "1",
53+
Usage: "set a number to be added in the scaffolded apiFile.txt",
54+
})
55+
} else if webhookFlag {
56+
pluginResponse.Flags = append(pluginResponse.Flags, external.Flag{
57+
Name: "hooked",
58+
Type: "bool",
59+
Default: "false",
60+
Usage: "add the word `hooked` to the end of the scaffolded webhookFile.txt",
61+
})
62+
} else {
63+
pluginResponse.Error = true
64+
pluginResponse.ErrorMsgs = []string{
65+
"unrecognized flag",
66+
}
67+
}
68+
69+
return pluginResponse
70+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log"
7+
8+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/external"
9+
)
10+
11+
// returnError is a helper function to return a JSON
12+
// response that states an error has occurred along
13+
// with the error message to Kubebuilder. If this
14+
// function encounters an error printing the JSON
15+
// response it just prints a normal error message
16+
// and exits with a non-zero exit code. Kubebuilder
17+
// will detect that an error has occurred if there is
18+
// a non-zero exit code from the external plugin, but
19+
// it is recommended to return a JSON response that states
20+
// an error has occurred to provide the best user experience
21+
// and integration with Kubebuilder.
22+
func returnError(err error) {
23+
errResponse := external.PluginResponse{
24+
Error: true,
25+
ErrorMsgs: []string{
26+
err.Error(),
27+
},
28+
}
29+
output, err := json.Marshal(errResponse)
30+
if err != nil {
31+
log.Fatalf("encountered error marshaling output: %s | OUTPUT: %s", err.Error(), output)
32+
}
33+
34+
fmt.Printf("%s", output)
35+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/pflag"
7+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/external"
8+
)
9+
10+
// initCmd handles all the logic for the `init` subcommand of this sample external plugin
11+
func initCmd(pr *external.PluginRequest) external.PluginResponse {
12+
pluginResponse := external.PluginResponse{
13+
APIVersion: "v1alpha1",
14+
Command: "init",
15+
Universe: pr.Universe,
16+
}
17+
18+
// Here is an example of parsing a flag from a Kubebuilder external plugin request
19+
flags := pflag.NewFlagSet("initFlags", pflag.ContinueOnError)
20+
flags.String("domain", "example.domain.com", "sets the domain added in the scaffolded initFile.txt")
21+
flags.Parse(pr.Args)
22+
domain, _ := flags.GetString("domain")
23+
24+
// Phase 2 Plugins uses the concept of a "universe" to represent the filesystem for a plugin.
25+
// This universe is a key:value mapping of filename:contents. Here we are adding the file
26+
// "initFile.txt" to the universe with some content. When this is returned Kubebuilder will
27+
// take all values within the "universe" and write them to the user's filesystem.
28+
pluginResponse.Universe["initFile.txt"] = fmt.Sprintf("A simple text file created with the `init` subcommand\nDOMAIN: %s", domain)
29+
30+
return pluginResponse
31+
}

0 commit comments

Comments
 (0)