Skip to content

Commit

Permalink
Allow configuration sink prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Daisy Guo committed Feb 28, 2020
1 parent 82381f3 commit 4b9cf7c
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
16 changes: 14 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,38 @@ 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

The default location `kn` looks for config is under the home directory of the user at `$HOME/.kn/config.yaml`. It is not created for you as part of the `kn` installation. You can create this file elsewhere and use the `--config` flag to specify its path.

### 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
```
----------------------------------------------------------

Expand Down
12 changes: 12 additions & 0 deletions pkg/kn/commands/flags/sink.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions pkg/kn/commands/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
20 changes: 18 additions & 2 deletions pkg/kn/core/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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())
},
}
Expand Down Expand Up @@ -225,7 +229,7 @@ func initConfig() {
}
}

func initConfigFlags() {
func initConfigFlags() error {
if viper.IsSet("plugins-dir") {
commands.Cfg.PluginsDir = viper.GetString("plugins-dir")
}
Expand All @@ -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) {
Expand Down
92 changes: 92 additions & 0 deletions test/e2e/sinkprefix_test.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 4b9cf7c

Please sign in to comment.