feat: `func config volumes` - interactive prompt (#391)

Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>
This commit is contained in:
Zbynek Roubalik 2021-06-17 09:21:07 +02:00 committed by GitHub
parent 6e8517c023
commit 4ba95b69a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 578 additions and 42 deletions

124
cmd/config.go Normal file
View File

@ -0,0 +1,124 @@
package cmd
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/ory/viper"
"github.com/spf13/cobra"
bosonFunc "github.com/boson-project/func"
)
func init() {
root.AddCommand(configCmd)
configCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
}
var configCmd = &cobra.Command{
Use: "config",
Short: "Configure a function",
Long: `Configure a function
Interactive propmt that allows configuration of Volume mounts and Environment variables for a function
project present in the current directory or from the directory specified with --path.
`,
SuggestFor: []string{"cfg", "cofnig"},
PreRunE: bindEnv("path"),
RunE: runConfigCmd,
}
func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(args)
if err != nil {
return
}
var qs = []*survey.Question{
{
Name: "selectedConfig",
Prompt: &survey.Select{
Message: "What do you want to configure?",
Options: []string{"Environment values", "Volumes"},
Default: "Environment values",
},
},
{
Name: "selectedOperation",
Prompt: &survey.Select{
Message: "What operation do you want to perform?",
Options: []string{"Add", "Remove", "List"},
Default: "List",
},
},
}
answers := struct {
SelectedConfig string
SelectedOperation string
}{}
err = survey.Ask(qs, &answers)
if err != nil {
if err == terminal.InterruptErr {
return nil
}
return
}
switch answers.SelectedOperation {
case "Add":
if answers.SelectedConfig == "Volumes" {
err = runAddVolumesPrompt(cmd.Context(), function)
}
case "Remove":
if answers.SelectedConfig == "Volumes" {
err = runRemoveVolumesPrompt(function)
}
case "List":
if answers.SelectedConfig == "Volumes" {
listVolumes(function)
}
}
return
}
// CLI Configuration (parameters)
// ------------------------------
type configCmdConfig struct {
Name string
Path string
Verbose bool
}
func newConfigCmdConfig(args []string) configCmdConfig {
var name string
if len(args) > 0 {
name = args[0]
}
return configCmdConfig{
Name: deriveName(name, viper.GetString("path")),
Path: viper.GetString("path"),
}
}
func initConfigCommand(args []string) (bosonFunc.Function, error) {
config := newConfigCmdConfig(args)
function, err := bosonFunc.NewFunction(config.Path)
if err != nil {
return bosonFunc.Function{}, err
}
// Check if the Function has been initialized
if !function.Initialized() {
return bosonFunc.Function{}, fmt.Errorf("the given path '%v' does not contain an initialized function", config.Path)
}
return function, nil
}

247
cmd/config_volumes.go Normal file
View File

@ -0,0 +1,247 @@
package cmd
import (
"context"
"fmt"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/spf13/cobra"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/k8s"
)
func init() {
configCmd.AddCommand(configVolumesCmd)
configVolumesCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
configVolumesCmd.AddCommand(configVolumesAddCmd)
configVolumesAddCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
configVolumesCmd.AddCommand(configVolumesRemoveCmd)
configVolumesRemoveCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
}
var configVolumesCmd = &cobra.Command{
Use: "volumes",
Short: "List and manage configured volumes for a function",
Long: `List and manage configured volumes for a function
Prints configured Volume mounts for a function project present in
the current directory or from the directory specified with --path.
`,
SuggestFor: []string{"volums", "volume", "vols"},
PreRunE: bindEnv("path"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(args)
if err != nil {
return
}
listVolumes(function)
return
},
}
var configVolumesAddCmd = &cobra.Command{
Use: "add",
Short: "Add volume to the function configuration",
Long: `Add volume to the function configuration
Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project
in the current directory or from the directory specified with --path.
`,
SuggestFor: []string{"ad", "create", "insert", "append"},
//ValidArgsFunction: CompleteFunctionList,
PreRunE: bindEnv("path"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(args)
if err != nil {
return
}
return runAddVolumesPrompt(cmd.Context(), function)
},
}
var configVolumesRemoveCmd = &cobra.Command{
Use: "remove",
Short: "Remove volume from the function configuration",
Long: `Remove volume from the function configuration
Interactive prompt to remove Volume mounts from the function project
in the current directory or from the directory specified with --path.
`,
SuggestFor: []string{"del", "delete", "rmeove"},
PreRunE: bindEnv("path"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(args)
if err != nil {
return
}
return runRemoveVolumesPrompt(function)
},
}
func listVolumes(f bosonFunc.Function) {
if len(f.Volumes) == 0 {
fmt.Println("There aren't any configured Volume mounts")
return
}
fmt.Println("Configured Volumes mounts:")
for _, v := range f.Volumes {
fmt.Println(" - ", v.String())
}
}
func runAddVolumesPrompt(ctx context.Context, f bosonFunc.Function) (err error) {
secrets, err := k8s.ListSecretsNames(ctx, f.Namespace)
if err != nil {
return
}
configMaps, err := k8s.ListConfigMapsNames(ctx, f.Namespace)
if err != nil {
return
}
// SECTION - select resource type to be mounted
options := []string{}
selectedOption := ""
const optionConfigMap = "ConfigMap"
const optionSecret = "Secret"
if len(configMaps) > 0 {
options = append(options, optionConfigMap)
}
if len(secrets) > 0 {
options = append(options, optionSecret)
}
switch len(options) {
case 0:
fmt.Printf("There aren't any Secrets or ConfiMaps in the namespace \"%s\"\n", f.Namespace)
return
case 1:
selectedOption = options[0]
case 2:
err = survey.AskOne(&survey.Select{
Message: "What do you want to mount as a Volume?",
Options: options,
}, &selectedOption)
if err != nil {
if err == terminal.InterruptErr {
return nil
}
return
}
}
// SECTION - select the specific resource to be mounted
optionsResoures := []string{}
resourceType := ""
switch selectedOption {
case optionConfigMap:
resourceType = optionConfigMap
optionsResoures = configMaps
case optionSecret:
resourceType = optionSecret
optionsResoures = secrets
}
selectedResource := ""
err = survey.AskOne(&survey.Select{
Message: fmt.Sprintf("Which \"%s\" do you want to mount?", resourceType),
Options: optionsResoures,
}, &selectedResource)
if err != nil {
if err == terminal.InterruptErr {
return nil
}
return
}
// SECTION - specify mount Path of the Volume
path := ""
err = survey.AskOne(&survey.Input{
Message: fmt.Sprintf("Please specify the path where the %s should be mounted:", resourceType),
}, &path, survey.WithValidator(func(val interface{}) error {
if str, ok := val.(string); !ok || len(str) <= 0 || !strings.HasPrefix(str, "/") {
return fmt.Errorf("The input must be non-empty absolute path.")
}
return nil
}))
if err != nil {
if err == terminal.InterruptErr {
return nil
}
return
}
// we have all necessary information -> let's store the new Volume
newVolume := bosonFunc.Volume{Path: &path}
switch selectedOption {
case optionConfigMap:
newVolume.ConfigMap = &selectedResource
case optionSecret:
newVolume.Secret = &selectedResource
}
f.Volumes = append(f.Volumes, newVolume)
err = f.WriteConfig()
if err == nil {
fmt.Println("Volume was added to the function configuration")
}
return
}
func runRemoveVolumesPrompt(f bosonFunc.Function) (err error) {
if len(f.Volumes) == 0 {
fmt.Println("There aren't any configured Volume mounts")
return
}
options := []string{}
for _, v := range f.Volumes {
options = append(options, v.String())
}
selectedVolume := ""
prompt := &survey.Select{
Message: "Which Volume do you want to remove?",
Options: options,
}
err = survey.AskOne(prompt, &selectedVolume)
if err != nil {
if err == terminal.InterruptErr {
return nil
}
return
}
var newVolumes bosonFunc.Volumes
removed := false
for i, v := range f.Volumes {
if v.String() == selectedVolume {
newVolumes = append(f.Volumes[:i], f.Volumes[i+1:]...)
removed = true
break
}
}
if removed {
f.Volumes = newVolumes
err = f.WriteConfig()
if err == nil {
fmt.Println("Volume was removed from the function configuration")
}
}
return
}

View File

@ -22,6 +22,16 @@ type Volume struct {
Path *string `yaml:"path"`
}
func (v Volume) String() string {
if v.ConfigMap != nil {
return fmt.Sprintf("ConfigMap \"%s\" mounted at path: \"%s\"", *v.ConfigMap, *v.Path)
} else if v.Secret != nil {
return fmt.Sprintf("Secret \"%s\" mounted at path: \"%s\"", *v.Secret, *v.Path)
}
return ""
}
type Envs []Env
type Env struct {
Name *string `yaml:"name,omitempty"`

View File

@ -159,3 +159,43 @@ kn func emit --path /path/to/fn -i fn.test
# Send a CloudEvent to an arbitrary endpoint
kn func emit --sink "http://my.event.broker.com"
```
## `config`
Invokes interactive prompt that manages configuration of the Function project in the current directory.
The user may specify a path to the project directory using the `--path` or `-p` flag. This command operates on configuration
specified in `func.yaml` configuration file.
Users need to deploy or update the function with `func deploy` in order to apply the updated configuration to the deployed function.
This command has subcommands `envs` and `volumes` to manage directly the specific resouces: Environment variables and Volumes.
These subcommands has commands `add` and `remove` to add and remove specified resouces.
Invokes top level interactive prompt that allows choosing the resouce and operation:
```console
func config [-p <path>]
```
Example:
```console
func config
? What do you want to configure? Volumes
? What operation do you want to perform? List
Configured Volumes mounts:
- Secret "mysecret" mounted at path: "/workspace/secret"
- ConfigMap "mycm" mounted at path: "/workspace/configmap"
```
This command lists configured Volumes:
```console
func config volumes [-p <path>]
```
Invokes interactive prompt that allows addind Volumes to the function configuration
```console
func config volumes add [-p <path>]
```
Invokes interactive prompt that allows removing Volumes from the function configuration
```console
func config volumes remove [-p <path>]
```

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/boson-project/func
go 1.15
require (
github.com/AlecAivazis/survey/v2 v2.2.12
github.com/buildpacks/pack v0.18.0
github.com/cloudevents/sdk-go/v2 v2.2.0
github.com/containers/image/v5 v5.10.5

10
go.sum
View File

@ -44,6 +44,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EU
contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0=
github.com/AlecAivazis/survey/v2 v2.2.12 h1:5a07y93zA6SZ09gOa9wLVLznF5zTJMQ+pJ3cZK4IuO8=
github.com/AlecAivazis/survey/v2 v2.2.12/go.mod h1:6d4saEvBsfSHXeN1a5OA5m2+HJ2LuVokllnC77pAIKI=
github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v42.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@ -96,6 +98,7 @@ github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3H
github.com/Microsoft/hcsshim v0.8.14 h1:lbPVK25c1cu5xTLITwpUcxoA9vKrKErASPYygvouJns=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@ -544,6 +547,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -585,6 +589,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
@ -604,6 +609,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -649,6 +655,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M=
@ -912,6 +919,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -1018,6 +1026,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -1160,6 +1169,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

37
k8s/client.go Normal file
View File

@ -0,0 +1,37 @@
package k8s
import (
"fmt"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func NewKubernetesClientset(namespace string) (*kubernetes.Clientset, error) {
restConfig, err := GetClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new kubernetes client: %v", err)
}
return kubernetes.NewForConfig(restConfig)
}
func GetNamespace(defaultNamespace string) (namespace string, err error) {
namespace = defaultNamespace
if defaultNamespace == "" {
namespace, _, err = GetClientConfig().Namespace()
if err != nil {
return
}
}
return
}
func GetClientConfig() clientcmd.ClientConfig {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{})
}

47
k8s/configmaps.go Normal file
View File

@ -0,0 +1,47 @@
package k8s
import (
"context"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func GetConfigMap(ctx context.Context, name, namespaceOverride string) (*corev1.ConfigMap, error) {
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return nil, err
}
client, err := NewKubernetesClientset(namespace)
if err != nil {
return nil, err
}
return client.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{})
}
func ListConfigMapsNames(ctx context.Context, namespaceOverride string) (names []string, err error) {
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return
}
client, err := NewKubernetesClientset(namespace)
if err != nil {
return
}
cms, err := client.CoreV1().ConfigMaps(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
return
}
for _, cm := range cms.Items {
names = append(names, cm.Name)
}
return
}

47
k8s/secrets.go Normal file
View File

@ -0,0 +1,47 @@
package k8s
import (
"context"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func GetSecret(ctx context.Context, name, namespaceOverride string) (*corev1.Secret, error) {
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return nil, err
}
client, err := NewKubernetesClientset(namespace)
if err != nil {
return nil, err
}
return client.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{})
}
func ListSecretsNames(ctx context.Context, namespaceOverride string) (names []string, err error) {
namespace, err := GetNamespace(namespaceOverride)
if err != nil {
return
}
client, err := NewKubernetesClientset(namespace)
if err != nil {
return
}
secrets, err := client.CoreV1().Secrets(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
return
}
for _, s := range secrets.Items {
names = append(names, s.Name)
}
return
}

View File

@ -4,12 +4,12 @@ import (
"fmt"
"time"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
clientservingv1 "knative.dev/client/pkg/serving/v1"
eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1"
servingv1 "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1"
"github.com/boson-project/func/k8s"
)
const (
@ -18,7 +18,7 @@ const (
func NewServingClient(namespace string) (clientservingv1.KnServingClient, error) {
restConfig, err := getClientConfig().ClientConfig()
restConfig, err := k8s.GetClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new serving client: %v", err)
}
@ -35,7 +35,7 @@ func NewServingClient(namespace string) (clientservingv1.KnServingClient, error)
func NewEventingClient(namespace string) (clienteventingv1beta1.KnEventingClient, error) {
restConfig, err := getClientConfig().ClientConfig()
restConfig, err := k8s.GetClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new serving client: %v", err)
}
@ -49,31 +49,3 @@ func NewEventingClient(namespace string) (clienteventingv1beta1.KnEventingClient
return client, nil
}
func NewKubernetesClientset(namespace string) (*kubernetes.Clientset, error) {
restConfig, err := getClientConfig().ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to create new kubernetes client: %v", err)
}
return kubernetes.NewForConfig(restConfig)
}
func GetNamespace(defaultNamespace string) (namespace string, err error) {
namespace = defaultNamespace
if defaultNamespace == "" {
namespace, _, err = getClientConfig().Namespace()
if err != nil {
return
}
}
return
}
func getClientConfig() clientcmd.ClientConfig {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{})
}

View File

@ -20,6 +20,7 @@ import (
v1 "knative.dev/serving/pkg/apis/serving/v1"
fn "github.com/boson-project/func"
"github.com/boson-project/func/k8s"
)
type Deployer struct {
@ -32,7 +33,7 @@ type Deployer struct {
func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
deployer = &Deployer{}
namespace, err := GetNamespace(namespaceOverride)
namespace, err := k8s.GetNamespace(namespaceOverride)
if err != nil {
return
}
@ -495,21 +496,17 @@ func processVolumes(volumes fn.Volumes, referencedSecrets, referencedConfigMaps
// checkSecretsConfigMapsArePresent returns error if Secrets or ConfigMaps
// referenced in input sets are not deployed on the cluster in the specified namespace
func checkSecretsConfigMapsArePresent(ctx context.Context, namespace string, referencedSecrets, referencedConfigMaps *sets.String) error {
client, err := NewKubernetesClientset(namespace)
if err != nil {
return err
}
errMsg := ""
for s := range *referencedSecrets {
_, err := client.CoreV1().Secrets(namespace).Get(ctx, s, metav1.GetOptions{})
_, err := k8s.GetSecret(ctx, s, namespace)
if err != nil {
errMsg += fmt.Sprintf(" referenced Secret \"%s\" is not present in namespace \"%s\"\n", s, namespace)
}
}
for cm := range *referencedConfigMaps {
_, err := client.CoreV1().ConfigMaps(namespace).Get(ctx, cm, metav1.GetOptions{})
_, err := k8s.GetConfigMap(ctx, cm, namespace)
if err != nil {
errMsg += fmt.Sprintf(" referenced ConfigMap \"%s\" is not present in namespace \"%s\"\n", cm, namespace)
}

View File

@ -8,6 +8,7 @@ import (
"knative.dev/eventing/pkg/apis/eventing/v1beta1"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/k8s"
)
type Describer struct {
@ -17,7 +18,7 @@ type Describer struct {
func NewDescriber(namespaceOverride string) (describer *Describer, err error) {
describer = &Describer{}
namespace, err := GetNamespace(namespaceOverride)
namespace, err := k8s.GetNamespace(namespaceOverride)
if err != nil {
return
}

View File

@ -7,6 +7,7 @@ import (
"knative.dev/pkg/apis"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/k8s"
)
const (
@ -22,7 +23,7 @@ type Lister struct {
func NewLister(namespaceOverride string) (l *Lister, err error) {
l = &Lister{}
namespace, err := GetNamespace(namespaceOverride)
namespace, err := k8s.GetNamespace(namespaceOverride)
if err != nil {
return
}

View File

@ -4,13 +4,15 @@ import (
"context"
"fmt"
"time"
"github.com/boson-project/func/k8s"
)
const RemoveTimeout = 120 * time.Second
func NewRemover(namespaceOverride string) (remover *Remover, err error) {
remover = &Remover{}
namespace, err := GetNamespace(namespaceOverride)
namespace, err := k8s.GetNamespace(namespaceOverride)
if err != nil {
return
}