Allow configuration sink prefixes (#676)

This commit is contained in:
Ying Chun Guo 2020-02-28 18:02:51 +08:00 committed by GitHub
parent 82381f36e4
commit d14c01fb5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 4 deletions

View File

@ -20,6 +20,10 @@
|===
| | Description | PR
| 🧽
| Allow configuration sink prefixes
| https://github.com/knative/client/pull/571[#571]
| 🧽
| Support multiple revisions on `kn revision delete`
| https://github.com/knative/client/pull/657[#657]

View File

@ -38,7 +38,7 @@ You'll need a `kubectl`-style config file to connect to your cluster.
## Kn Config
There are a set of configuration parameters you can setup to better customize `kn`. In particular, you can specify where your `kn` plugins are located and how they are found. The `kn` configuration file is meant to capture these configuration options. Let's explore this file's location, and the options you are able to change with it.
There are a set of configuration parameters you can setup to better customize `kn`. For example, you can specify where your `kn` plugins are located and how they are found, and you can specify the prefix for your addressable `sink` objects. The `kn` configuration file is meant to capture these configuration options. Let's explore this file's location, and the options you are able to change with it.
### Location
@ -46,18 +46,30 @@ The default location `kn` looks for config is under the home directory of the us
### Options
There are two options you can specify in the `kn` config file and they are related to how `kn` locates plugins.
Below are the options you can specify in the `kn` config file.
1. `pluginsDir` which is the same as the persistent flag `--plugins-dir` and specifies the kn plugins directory. It defaults to: `~/.kn/plugins`. By using the persistent flag (when you issue a command) or by specifying the value in the `kn` config, a user can select which directory to find `kn` plugins. It can be any directory that is visible to the user.
2. `lookupPluginsInPath` which is the same as the persistent flag `--lookup-plugins-in-path` and specficies if `kn` should look for plugins anywhere in the specified `PATH` environment variable. This is a boolean configuration option and the default value is `false`.
3. `sink` defines your prefix to refer to Kubernetes addressable resources. To configure a sink prefix, define following in the config file:
1. `prefix`: Prefix you want to describe your sink as. `service` or `svc` (`serving.knative.dev/v1`) and `broker` (`eventing.knative.dev/v1alpha1`) are predefined prefixes in `kn`. These predefined prefixes can be overridden by values in configuration file.
2. `group`: The APIGroup of Kubernetes resource.
3. `version`: The version of Kubernetes resources.
4. `resource`: The plural name of Kubernetes resources (for example: services).
For example, the following `kn` config will look for `kn` plugins in the user's `PATH` and also execute plugin in `~/.kn/plugins`.
It also defines a sink prefix `myprefix` which refers to `brokers` in `eventing.knative.dev/v1alpha1`. With this configuration, you can use `myprefix:default` to describe a Broker `default` in `kn` command line.
```bash
cat ~/.kn/config.yaml
lookupPluginsInPath: true
pluginsdir: ~/.kn/plugins
sink:
- prefix: myprefix
group: eventing.knative.dev
version: v1alpha1
resource: brokers
```
----------------------------------------------------------

View File

@ -25,6 +25,7 @@ import (
duckv1 "knative.dev/pkg/apis/duck/v1"
clientdynamic "knative.dev/client/pkg/dynamic"
"knative.dev/client/pkg/kn/commands"
)
type SinkFlags struct {
@ -55,6 +56,17 @@ var SinkPrefixes = map[string]schema.GroupVersionResource{
},
}
func ConfigSinkPrefixes(prefixes []commands.SinkPrefixConfig) {
for _, p := range prefixes {
//user configration might override the default configuration
SinkPrefixes[p.Prefix] = schema.GroupVersionResource{
Resource: p.Resource,
Group: p.Group,
Version: p.Version,
}
}
}
// ResolveSink returns the Destination referred to by the flags in the acceptor.
// It validates that any object the user is referring to exists.
func (i *SinkFlags) ResolveSink(knclient clientdynamic.KnDynamicClient, namespace string) (*duckv1.Destination, error) {

View File

@ -48,6 +48,15 @@ var Cfg Config = Config{
type Config struct {
PluginsDir string
LookupPlugins *bool
SinkPrefixes []SinkPrefixConfig
}
// SinkPrefixConfig is the struct of sink prefix config in kn config
type SinkPrefixConfig struct {
Prefix string
Resource string
Group string
Version string
}
// KnParams for creating commands. Useful for inserting mocks for testing.

View File

@ -31,6 +31,7 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/kn/commands/completion"
cmdflags "knative.dev/client/pkg/kn/commands/flags"
"knative.dev/client/pkg/kn/commands/plugin"
"knative.dev/client/pkg/kn/commands/revision"
"knative.dev/client/pkg/kn/commands/route"
@ -126,7 +127,10 @@ func NewKnCommand(params ...commands.KnParams) *cobra.Command {
SilenceErrors: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
initConfigFlags()
err := initConfigFlags()
if err != nil {
return err
}
return flags.ReconcileBoolFlags(cmd.Flags())
},
}
@ -225,7 +229,7 @@ func initConfig() {
}
}
func initConfigFlags() {
func initConfigFlags() error {
if viper.IsSet("plugins-dir") {
commands.Cfg.PluginsDir = viper.GetString("plugins-dir")
}
@ -234,6 +238,18 @@ func initConfigFlags() {
var aBool bool
aBool = viper.GetBool("lookup-plugins")
commands.Cfg.LookupPlugins = &aBool
// set the Cfg.SinkPrefixes from viper if sink is configured
if viper.IsSet("sink") {
err := viper.UnmarshalKey("sink", &commands.Cfg.SinkPrefixes)
if err != nil {
return fmt.Errorf("unable to parse sink prefixes configuration in file %s because of %v",
viper.ConfigFileUsed(), err)
}
cmdflags.ConfigSinkPrefixes(commands.Cfg.SinkPrefixes)
}
return nil
}
func extractKnPluginFlags(args []string) (string, bool, error) {

View File

@ -0,0 +1,92 @@
// Copyright 2020 The Knative Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or im
// See the License for the specific language governing permissions and
// limitations under the License.
// +build e2e
package e2e
import (
"io/ioutil"
"os"
"testing"
"gotest.tools/assert"
"knative.dev/client/pkg/util"
)
const (
KnConfigContent string = `sink:
- group: serving.knative.dev
prefix: hello
resource: services
version: v1`
)
type sinkprefixTestConfig struct {
knConfigDir string
knConfigPath string
}
func (tc *sinkprefixTestConfig) setup() error {
var err error
tc.knConfigDir, err = ioutil.TempDir("", "kn1-config")
if err != nil {
return err
}
tc.knConfigPath, err = createPluginFile("config.yaml", KnConfigContent, tc.knConfigDir, FileModeReadWrite)
if err != nil {
return err
}
return nil
}
func (tc *sinkprefixTestConfig) teardown() {
os.RemoveAll(tc.knConfigDir)
}
func TestSinkPrefixConfig(t *testing.T) {
t.Parallel()
test, err := NewE2eTest()
assert.NilError(t, err)
defer func() {
assert.NilError(t, test.Teardown())
}()
r := NewKnRunResultCollector(t)
defer r.DumpIfFailed()
tc := sinkprefixTestConfig{}
assert.NilError(t, tc.setup())
defer tc.teardown()
t.Log("Creating a testservice")
test.serviceCreate(t, r, "testsvc0")
t.Log("create cronJob sources with a sink to hello:testsvc0")
test.cronJobSourceCreateWithConfig(t, r, "testcronjobsource0", "* * * * */1", "ping", "hello:testsvc0", tc.knConfigPath)
jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}"
out, err := test.getResourceFieldsWithJSONPath("cronjobsource", "testcronjobsource0", jpSinkRefNameInSpec)
assert.NilError(t, err)
assert.Equal(t, out, "testsvc0")
t.Log("delete cronJob sources")
test.cronJobSourceDelete(t, r, "testcronjobsource0")
}
func (test *e2eTest) cronJobSourceCreateWithConfig(t *testing.T, r *KnRunResultCollector, sourceName string, schedule string, data string, sink string, config string) {
out := test.kn.Run("source", "cronjob", "create", sourceName,
"--schedule", schedule, "--data", data, "--sink", sink, "--config", config)
assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "cronjob", "source", sourceName, "created", "namespace", test.kn.namespace))
r.AssertNoError(out)
}