Skip to content

Commit

Permalink
Channel type aliases via kn config and alias for InMemoryChannel
Browse files Browse the repository at this point in the history
 - User can now configure channel type aliases in kn config and specify
   alias to GVK mappings for easy reference on CLI and refer with `--type` flag
 - User can also use inbuilt alias 'imc' for InMemoryChannel
  • Loading branch information
navidshaikh committed Aug 13, 2020
1 parent 4990f9a commit c853c40
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 9 deletions.
6 changes: 4 additions & 2 deletions docs/cmd/kn_channel_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ kn channel create NAME
# Create a channel 'pipe' with default setting for channel configuration
kn channel create pipe
# Create a channel 'imc1' of type InMemoryChannel
# Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc'
kn channel create imc1 --type imc
# same as above without using inbuilt alias but providing explicit GVK
kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel
# Create a channel 'k1' of type KafkaChannel
Expand All @@ -29,7 +31,7 @@ kn channel create NAME
```
-h, --help help for create
-n, --namespace string Specify the namespace to operate in.
--type string Type of the channel to create in the format 'Group:Version:Kind'. For example: '--type messaging.knative.dev:v1alpha1:KafkaChannel'. Default is to use messaging layer setting for default channel configuration.
--type string Override channel type to create, in the format '--type Group:Version:Kind'. If flag is not specified, it uses default messaging layer settings for channel type, cluster wide or specific namespace. You can configure aliases for channel types in kn config and refer the aliases with this flag. You can also refer inbuilt channel type InMemoryChannel using an alias 'imc' like '--type imc'. Examples: '--type messaging.knative.dev:v1alpha1:KafkaChannel' for specifying explicit Group:Version:Kind.
```

### Options inherited from parent commands
Expand Down
10 changes: 7 additions & 3 deletions pkg/kn/commands/channel/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ import (

knerrors "knative.dev/client/pkg/errors"
"knative.dev/client/pkg/kn/commands"
knflags "knative.dev/client/pkg/kn/flags"
knmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
)

// NewChannelCreateCommand to create event channels
func NewChannelCreateCommand(p *commands.KnParams) *cobra.Command {
var ctypeFlags knflags.ChannelTypeFlags
cmd := &cobra.Command{
Use: "create NAME",
Short: "Create an event channel",
Example: `
# Create a channel 'pipe' with default setting for channel configuration
kn channel create pipe
# Create a channel 'imc1' of type InMemoryChannel
# Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc'
kn channel create imc1 --type imc
# same as above without using inbuilt alias but providing explicit GVK
kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel
# Create a channel 'k1' of type KafkaChannel
Expand All @@ -61,7 +65,7 @@ func NewChannelCreateCommand(p *commands.KnParams) *cobra.Command {
cb := knmessagingv1beta1.NewChannelBuilder(name)

if cmd.Flag("type").Changed {
gvk, err := processType(cmd.Flag("type").Value.String())
gvk, err := ctypeFlags.Parse()
if err != nil {
return err
}
Expand All @@ -78,7 +82,7 @@ func NewChannelCreateCommand(p *commands.KnParams) *cobra.Command {
},
}
commands.AddNamespaceFlags(cmd.Flags(), false)
cmd.Flags().String("type", "", "Type of the channel to create in the format 'Group:Version:Kind'. For example: '--type messaging.knative.dev:v1alpha1:KafkaChannel'. Default is to use messaging layer setting for default channel configuration.")
ctypeFlags.Add(cmd)
return cmd
}

Expand Down
25 changes: 25 additions & 0 deletions pkg/kn/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ type config struct {

// sinkMappings is a list of sink mapping
sinkMappings []SinkMapping

// channelTypeMappings is a list of channel type mapping
channelTypeMappings []ChannelTypeMapping
}

// ConfigFile returns the config file which is either the default XDG conform
Expand Down Expand Up @@ -84,6 +87,10 @@ func (c *config) SinkMappings() []SinkMapping {
return c.sinkMappings
}

func (c *config) ChannelTypeMappings() []ChannelTypeMapping {
return c.channelTypeMappings
}

// Config used for flag binding
var globalConfig = config{}

Expand Down Expand Up @@ -143,6 +150,12 @@ func BootstrapConfig() error {

// Deserialize sink mappings if configured
err = parseSinkMappings()
if err != nil {
return err
}

// Deserialize channel type mappings if configured
err = parseChannelTypeMappings()
return err
}

Expand Down Expand Up @@ -243,6 +256,18 @@ func parseSinkMappings() error {
return nil
}

// parse channel type mappings and store them in the global configuration
func parseChannelTypeMappings() error {
if viper.IsSet(keyChannelTypeMappings) {
err := viper.UnmarshalKey(keyChannelTypeMappings, &globalConfig.channelTypeMappings)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error while parsing channel type mappings in configuration file %s",
viper.ConfigFileUsed()))
}
}
return nil
}

// Prepare the default config file for the usage message
func defaultConfigFileForUsageMessage() string {
if runtime.GOOS == "windows" {
Expand Down
12 changes: 12 additions & 0 deletions pkg/kn/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ eventing:
resource: services
group: core
version: v1
channel-type-mappings:
- alias: kafka
kind: KafkaChannel
group: messaging.knative.dev
version: v1alpha1
`

configFile, cleanup := setupConfig(t, configYaml)
Expand All @@ -55,6 +60,13 @@ eventing:
Group: "core",
Version: "v1",
})
assert.Equal(t, len(GlobalConfig.ChannelTypeMappings()), 1)
assert.DeepEqual(t, (GlobalConfig.ChannelTypeMappings())[0], ChannelTypeMapping{
Alias: "kafka",
Kind: "KafkaChannel",
Group: "messaging.knative.dev",
Version: "v1alpha1",
})
}

func TestBootstrapConfigWithoutConfigFile(t *testing.T) {
Expand Down
10 changes: 6 additions & 4 deletions pkg/kn/config/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ type TestConfig struct {
TestConfigFile string
TestLookupPluginsInPath bool
TestSinkMappings []SinkMapping
TestChannelTypeMappings []ChannelTypeMapping
}

// Ensure that TestConfig implements the configuration interface
var _ Config = &TestConfig{}

func (t TestConfig) PluginsDir() string { return t.TestPluginsDir }
func (t TestConfig) ConfigFile() string { return t.TestConfigFile }
func (t TestConfig) LookupPluginsInPath() bool { return t.TestLookupPluginsInPath }
func (t TestConfig) SinkMappings() []SinkMapping { return t.TestSinkMappings }
func (t TestConfig) PluginsDir() string { return t.TestPluginsDir }
func (t TestConfig) ConfigFile() string { return t.TestConfigFile }
func (t TestConfig) LookupPluginsInPath() bool { return t.TestLookupPluginsInPath }
func (t TestConfig) SinkMappings() []SinkMapping { return t.TestSinkMappings }
func (t TestConfig) ChannelTypeMappings() []ChannelTypeMapping { return t.TestChannelTypeMappings }
2 changes: 2 additions & 0 deletions pkg/kn/config/testing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ func TestTestConfig(t *testing.T) {
TestConfigFile: "configFile",
TestLookupPluginsInPath: true,
TestSinkMappings: nil,
TestChannelTypeMappings: nil,
}

assert.Equal(t, cfg.PluginsDir(), "pluginsDir")
assert.Equal(t, cfg.ConfigFile(), "configFile")
assert.Assert(t, cfg.LookupPluginsInPath())
assert.Assert(t, cfg.SinkMappings() == nil)
assert.Assert(t, cfg.ChannelTypeMappings() == nil)
}
20 changes: 20 additions & 0 deletions pkg/kn/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type Config interface {

// SinkMappings returns additional mappings for sink prefixes to resources
SinkMappings() []SinkMapping

// ChannelTypeMappings returns additional mappings for channel type aliases
ChannelTypeMappings() []ChannelTypeMapping
}

// SinkMappings is the struct of sink prefix config in kn config
Expand All @@ -49,11 +52,28 @@ type SinkMapping struct {
Version string
}

// ChannelTypeMapping is the struct of ChannelType alias config in kn config
type ChannelTypeMapping struct {

// Alias is the mapping alias (like "kafka")
Alias string

// Kind is the name for the mapped resource kind (like "KafkaChannel")
Kind string

// Group is the API group for the mapped resource kind (like "messaging.knative.dev")
Group string

// Version is the API version for the mapped resource kind (like "v1alpha1")
Version string
}

// config Keys for looking up in viper
const (
keyPluginsDirectory = "plugins.directory"
keyPluginsLookupInPath = "plugins.path-lookup"
keySinkMappings = "eventing.sink-mappings"
keyChannelTypeMappings = "eventing.channel-type-mappings"
)

// legacy config keys, deprecated
Expand Down
76 changes: 76 additions & 0 deletions pkg/kn/flags/channel_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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 implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flags

import (
"fmt"
"strings"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/schema"

"knative.dev/client/pkg/kn/config"
)

type ChannelTypeFlags struct {
ctype string
}

func (i *ChannelTypeFlags) Add(cmd *cobra.Command) {
cmd.Flags().StringVar(&i.ctype,
"type",
"",
"Override channel type to create, in the format '--type Group:Version:Kind'. "+
"If flag is not specified, it uses default messaging layer settings for channel type, cluster wide or specific namespace. "+
"You can configure aliases for channel types in kn config and refer the aliases with this flag. "+
"You can also refer inbuilt channel type InMemoryChannel using an alias 'imc' like '--type imc'. "+
"Examples: '--type messaging.knative.dev:v1alpha1:KafkaChannel' for specifying explicit Group:Version:Kind.")

for _, p := range config.GlobalConfig.ChannelTypeMappings() {
//user configration might override the default configuration
ctypeMappings[p.Alias] = schema.GroupVersionKind{
Kind: p.Kind,
Group: p.Group,
Version: p.Version,
}
}
}

// ctypeMappings maps aliases used for channel types to their GroupVersionKind
var ctypeMappings = map[string]schema.GroupVersionKind{
"imc": {
Group: "messaging.knative.dev",
Version: "v1beta1",
Kind: "InMemoryChannel",
},
}

func (i *ChannelTypeFlags) Parse() (*schema.GroupVersionKind, error) {
parts := strings.Split(i.ctype, ":")
switch len(parts) {
case 1:
if typ, ok := ctypeMappings[i.ctype]; ok {
return &typ, nil
}
return nil, fmt.Errorf("Error: unsupported channel type alias: '%s'", parts)
case 3:
if parts[0] == "" || parts[1] == "" || parts[2] == "" {
return nil, fmt.Errorf("Error: incorrect value '%s' for '--type', must be in the format 'Group:Version:Kind'", i.ctype)
}
return &schema.GroupVersionKind{Group: parts[0], Version: parts[1], Kind: parts[2]}, nil
default:
return nil, fmt.Errorf("Error: incorrect value '%s' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", i.ctype)
}
}

0 comments on commit c853c40

Please sign in to comment.