You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2019/12/18 10:30:01 UTC
[camel-k] 01/10: Allow to configure kamel CLI with env vars and
configuration files #1108
This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 24efaa0f1fd5b9b1489a324b7a512194bd45e041
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Wed Nov 27 18:22:19 2019 +0100
Allow to configure kamel CLI with env vars and configuration files #1108
---
go.mod | 2 +
go.sum | 11 ++
pkg/cmd/builder.go | 15 ++-
pkg/cmd/delete.go | 17 +--
pkg/cmd/describe_integration.go | 3 +-
pkg/cmd/describe_kit.go | 7 +-
pkg/cmd/describe_platform.go | 7 +-
pkg/cmd/get.go | 9 +-
pkg/cmd/install.go | 237 +++++++++++++++++++---------------
pkg/cmd/kit_create.go | 74 +++++------
pkg/cmd/kit_delete.go | 27 ++--
pkg/cmd/kit_get.go | 25 ++--
pkg/cmd/log.go | 13 +-
pkg/cmd/operator.go | 17 +--
pkg/cmd/rebuild.go | 9 +-
pkg/cmd/reset.go | 21 +--
pkg/cmd/root.go | 35 ++++-
pkg/cmd/{operator.go => root_test.go} | 27 +---
pkg/cmd/run.go | 102 ++++++++-------
pkg/cmd/util.go | 144 +++++++++++++++++++++
20 files changed, 495 insertions(+), 307 deletions(-)
diff --git a/go.mod b/go.mod
index 5af83f5..3f5c829 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
github.com/coreos/prometheus-operator v0.29.0
github.com/evanphx/json-patch v4.5.0+incompatible
github.com/fatih/structs v1.1.0
+ github.com/gertd/go-pluralize v0.1.1
github.com/go-logr/logr v0.1.0
github.com/google/go-containerregistry v0.0.0-20190206233756-dbc4da98389f // indirect
github.com/google/uuid v1.1.1
@@ -23,6 +24,7 @@ require (
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.3
+ github.com/spf13/viper v1.4.0
github.com/stoewer/go-strcase v1.0.2
github.com/stretchr/testify v1.3.0
go.uber.org/multierr v1.1.0
diff --git a/go.sum b/go.sum
index c55c3c8..c21e98d 100644
--- a/go.sum
+++ b/go.sum
@@ -13,6 +13,7 @@ github.com/Azure/azure-sdk-for-go v21.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
@@ -137,6 +138,8 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/gertd/go-pluralize v0.1.1 h1:fQhql/WRRwr4TVp+TCw12s2esCacvEVBdkTUUwNqF/Q=
+github.com/gertd/go-pluralize v0.1.1/go.mod h1:t5DfHcumb6m0RqyVJDrDLEzL2AGeaiqUXIcDNwLaeAs=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -276,6 +279,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/heketi/heketi v0.0.0-20181109135656-558b29266ce0/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o=
github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI=
@@ -335,6 +339,7 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA=
github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
@@ -360,6 +365,7 @@ github.com/miekg/dns v0.0.0-20160614162101-5d001d020961/go.mod h1:W1PPwlIAgtquWB
github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=
github.com/mistifyio/go-zfs v0.0.0-20151009155749-1b4ae6fb4e77/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
@@ -417,6 +423,7 @@ github.com/operator-framework/operator-sdk v0.12.0 h1:9eAD1L8e6pPCpFCAacBUVf2elo
github.com/operator-framework/operator-sdk v0.12.0/go.mod h1:mW8isQxiXlLCVf2E+xqflkQAVLOTbiqjndKdkKIrR0M=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@@ -492,14 +499,17 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -508,6 +518,7 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v0.0.0-20160820190039-7fb2782df3d8/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
github.com/stoewer/go-strcase v1.0.2 h1:l3iQ2FPu8+36ars/7syO1dQAkjwMCb1IE3J+Th0ohfE=
diff --git a/pkg/cmd/builder.go b/pkg/cmd/builder.go
index adb9509..9517e7d 100644
--- a/pkg/cmd/builder.go
+++ b/pkg/cmd/builder.go
@@ -27,21 +27,22 @@ func newCmdBuilder(rootCmdOptions *RootCmdOptions) *cobra.Command {
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
- Use: "builder",
- Short: "Run the Camel K builder",
- Long: `Run the Camel K builder`,
- Hidden: true,
- Run: impl.run,
+ Use: "builder",
+ Short: "Run the Camel K builder",
+ Long: `Run the Camel K builder`,
+ Hidden: true,
+ PreRunE: decode(&impl),
+ Run: impl.run,
}
- cmd.Flags().StringVar(&impl.BuildName, "build-name", "", "The name of the build resource")
+ cmd.Flags().String("build-name", "", "The name of the build resource")
return &cmd
}
type builderCmdOptions struct {
*RootCmdOptions
- BuildName string
+ BuildName string `mapstructure:"build-name"`
}
func (o *builderCmdOptions) run(_ *cobra.Command, _ []string) {
diff --git a/pkg/cmd/delete.go b/pkg/cmd/delete.go
index 6eeda59..a3d9a55 100644
--- a/pkg/cmd/delete.go
+++ b/pkg/cmd/delete.go
@@ -36,8 +36,9 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
- Use: "delete [integration1] [integration2] ...",
- Short: "Delete integrations deployed on Kubernetes",
+ Use: "delete [integration1] [integration2] ...",
+ Short: "Delete integrations deployed on Kubernetes",
+ PreRunE: decode(&impl),
RunE: func(_ *cobra.Command, args []string) error {
if err := impl.validate(args); err != nil {
return err
@@ -50,21 +51,21 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
},
}
- cmd.Flags().BoolVar(&impl.deleteAll, "all", false, "Delete all integrations")
+ cmd.Flags().Bool("all", false, "Delete all integrations")
return &cmd
}
type deleteCmdOptions struct {
*RootCmdOptions
- deleteAll bool
+ DeleteAll bool `mapstructure:"all"`
}
func (command *deleteCmdOptions) validate(args []string) error {
- if command.deleteAll && len(args) > 0 {
+ if command.DeleteAll && len(args) > 0 {
return errors.New("invalid combination: both all flag and named integrations are set")
}
- if !command.deleteAll && len(args) == 0 {
+ if !command.DeleteAll && len(args) == 0 {
return errors.New("invalid combination: neither all flag nor named integrations are set")
}
@@ -76,7 +77,7 @@ func (command *deleteCmdOptions) run(args []string) error {
if err != nil {
return err
}
- if len(args) != 0 && !command.deleteAll {
+ if len(args) != 0 && !command.DeleteAll {
for _, arg := range args {
name := kubernetes.SanitizeName(arg)
err := DeleteIntegration(command.Context, c, name, command.Namespace)
@@ -90,7 +91,7 @@ func (command *deleteCmdOptions) run(args []string) error {
fmt.Println("Integration " + name + " deleted")
}
}
- } else if command.deleteAll {
+ } else if command.DeleteAll {
integrationList := v1alpha1.IntegrationList{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
diff --git a/pkg/cmd/describe_integration.go b/pkg/cmd/describe_integration.go
index 117868f..25882f4 100644
--- a/pkg/cmd/describe_integration.go
+++ b/pkg/cmd/describe_integration.go
@@ -41,6 +41,7 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
Aliases: []string{"it"},
Short: "Describe an Integration",
Long: `Describe an Integration.`,
+ PreRunE: decode(&impl),
RunE: func(_ *cobra.Command, args []string) error {
if err := impl.validate(args); err != nil {
return err
@@ -60,7 +61,7 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
type describeIntegrationCommand struct {
*RootCmdOptions
- showSourceContent bool
+ showSourceContent bool `mapstructure:"show-source-content"`
}
func (command *describeIntegrationCommand) validate(args []string) error {
diff --git a/pkg/cmd/describe_kit.go b/pkg/cmd/describe_kit.go
index c182650..a3ce855 100644
--- a/pkg/cmd/describe_kit.go
+++ b/pkg/cmd/describe_kit.go
@@ -34,9 +34,10 @@ func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "kit",
- Short: "Describe an Integration Kit",
- Long: `Describe an Integration Kit.`,
+ Use: "kit",
+ Short: "Describe an Integration Kit",
+ Long: `Describe an Integration Kit.`,
+ PreRunE: decode(impl),
RunE: func(_ *cobra.Command, args []string) error {
if err := impl.validate(args); err != nil {
return err
diff --git a/pkg/cmd/describe_platform.go b/pkg/cmd/describe_platform.go
index 162a7a0..17c639b 100644
--- a/pkg/cmd/describe_platform.go
+++ b/pkg/cmd/describe_platform.go
@@ -34,9 +34,10 @@ func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "platform",
- Short: "Describe an Integration Platform",
- Long: `Describe an Integration Platform.`,
+ Use: "platform",
+ Short: "Describe an Integration Platform",
+ Long: `Describe an Integration Platform.`,
+ PreRunE: decode(impl),
RunE: func(_ *cobra.Command, args []string) error {
if err := impl.validate(args); err != nil {
return err
diff --git a/pkg/cmd/get.go b/pkg/cmd/get.go
index 6774065..d5dea19 100644
--- a/pkg/cmd/get.go
+++ b/pkg/cmd/get.go
@@ -39,10 +39,11 @@ func newCmdGet(rootCmdOptions *RootCmdOptions) *cobra.Command {
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
- Use: "get [integration]",
- Short: "Get integrations deployed on Kubernetes",
- Long: `Get the status of integrations deployed on on Kubernetes.`,
- RunE: options.run,
+ Use: "get [integration]",
+ Short: "Get integrations deployed on Kubernetes",
+ Long: `Get the status of integrations deployed on on Kubernetes.`,
+ PreRunE: decode(&options),
+ RunE: options.run,
}
return &cmd
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 56f8c33..bc10726 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -38,6 +38,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
+ "github.com/spf13/viper"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -49,45 +50,53 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
Use: "install",
- Short: "Install Camel K on a Kubernetes cluster",
+ Short: "Installs Camel K on a Kubernetes cluster",
Long: `Installs Camel K on a Kubernetes or OpenShift cluster.`,
- PreRunE: impl.validate,
- RunE: impl.install,
+ PreRunE: impl.decode,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := impl.validate(cmd, args); err != nil {
+ return err
+ }
+ if err := impl.install(cmd, args); err != nil {
+ return err
+ }
+ return nil
+ },
}
- cmd.Flags().BoolVarP(&impl.wait, "wait", "w", false, "Waits for the platform to be running")
- cmd.Flags().BoolVar(&impl.clusterSetupOnly, "cluster-setup", false, "Execute cluster-wide operations only (may require admin rights)")
- cmd.Flags().StringVar(&impl.clusterType, "cluster-type", "", "Set explicitly the cluster type to Kubernetes or OpenShift")
- cmd.Flags().BoolVar(&impl.skipOperatorSetup, "skip-operator-setup", false, "Do not install the operator in the namespace (in case there's a global one)")
- cmd.Flags().BoolVar(&impl.skipClusterSetup, "skip-cluster-setup", false, "Skip the cluster-setup phase")
- cmd.Flags().BoolVar(&impl.exampleSetup, "example", false, "Install example integration")
- cmd.Flags().BoolVar(&impl.global, "global", false, "Configure the operator to watch all namespaces. No integration platform is created.")
-
- cmd.Flags().StringVarP(&impl.outputFormat, "output", "o", "", "Output format. One of: json|yaml")
- cmd.Flags().StringVar(&impl.registry.Organization, "organization", "", "A organization on the Docker registry that can be used to publish images")
- cmd.Flags().StringVar(&impl.registry.Address, "registry", "", "A Docker registry that can be used to publish images")
- cmd.Flags().StringVar(&impl.registry.Secret, "registry-secret", "", "A secret used to push/pull images to the Docker registry")
- cmd.Flags().BoolVar(&impl.registry.Insecure, "registry-insecure", false, "Configure to configure registry access in insecure mode or not")
- cmd.Flags().StringVar(&impl.registryAuth.Server, "registry-auth-server", "", "The docker registry authentication server")
- cmd.Flags().StringVar(&impl.registryAuth.Username, "registry-auth-username", "", "The docker registry authentication username")
- cmd.Flags().StringVar(&impl.registryAuth.Password, "registry-auth-password", "", "The docker registry authentication password")
- cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property")
- cmd.Flags().StringVar(&impl.camelVersion, "camel-version", "", "Set the camel version")
- cmd.Flags().StringVar(&impl.runtimeVersion, "runtime-version", "", "Set the camel-k runtime version")
- cmd.Flags().StringVar(&impl.baseImage, "base-image", "", "Set the base image used to run integrations")
- cmd.Flags().StringVar(&impl.operatorImage, "operator-image", "", "Set the operator image used for the operator deployment")
- cmd.Flags().StringSliceVar(&impl.kits, "kit", nil, "Add an integration kit to build at startup")
- cmd.Flags().StringVar(&impl.buildStrategy, "build-strategy", "", "Set the build strategy")
- cmd.Flags().StringVar(&impl.buildTimeout, "build-timeout", "", "Set how long the build process can last")
- cmd.Flags().StringVar(&impl.traitProfile, "trait-profile", "", "The profile to use for traits")
- cmd.Flags().BoolVar(&impl.kanikoBuildCache, "kaniko-build-cache", true, "To enable or disable the Kaniko Cache in building phase")
- cmd.Flags().StringVar(&impl.httpProxySecret, "http-proxy-secret", "", "Configure the source of the secret holding HTTP proxy server details "+
+ cmd.Flags().BoolP("wait", "w", false, "Waits for the platform to be running")
+ cmd.Flags().Bool("cluster-setup", false, "Execute cluster-wide operations only (may require admin rights)")
+ cmd.Flags().String("cluster-type", "", "Set explicitly the cluster type to Kubernetes or OpenShift")
+ cmd.Flags().Bool("skip-operator-setup", false, "Do not install the operator in the namespace (in case there's a global one)")
+ cmd.Flags().Bool("skip-cluster-setup", false, "Skip the cluster-setup phase")
+ cmd.Flags().Bool("example", false, "Install example integration")
+ cmd.Flags().Bool("global", false, "Configure the operator to watch all namespaces. No integration platform is created.")
+
+ cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
+ cmd.Flags().String("organization", "", "A organization on the Docker registry that can be used to publish images")
+ cmd.Flags().String("registry", "", "A Docker registry that can be used to publish images")
+ cmd.Flags().String("registry-secret", "", "A secret used to push/pull images to the Docker registry")
+ cmd.Flags().Bool("registry-insecure", false, "Configure to configure registry access in insecure mode or not")
+ cmd.Flags().String("registry-auth-server", "", "The docker registry authentication server")
+ cmd.Flags().String("registry-auth-username", "", "The docker registry authentication username")
+ cmd.Flags().String("registry-auth-password", "", "The docker registry authentication password")
+ cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+ cmd.Flags().String("camel-version", "", "Set the camel version")
+ cmd.Flags().String("runtime-version", "", "Set the camel-k runtime version")
+ cmd.Flags().String("base-image", "", "Set the base Image used to run integrations")
+ cmd.Flags().String("operator-image", "", "Set the operator Image used for the operator deployment")
+ cmd.Flags().StringArray("kit", nil, "Add an integration kit to build at startup")
+ cmd.Flags().String("build-strategy", "", "Set the build strategy")
+ cmd.Flags().String("build-timeout", "", "Set how long the build process can last")
+ cmd.Flags().String("trait-profile", "", "The profile to use for traits")
+ cmd.Flags().Bool("kaniko-build-cache", true, "To enable or disable the Kaniko Cache in building phase")
+ cmd.Flags().String("http-proxy-secret", "", "Configure the source of the secret holding HTTP proxy server details "+
"(HTTP_PROXY|HTTPS_PROXY|NO_PROXY)")
// maven settings
- cmd.Flags().StringVar(&impl.localRepository, "local-repository", "", "Location of the local maven repository")
- cmd.Flags().StringVar(&impl.mavenSettings, "maven-settings", "", "Configure the source of the maven settings (configmap|secret:name[/key])")
- cmd.Flags().StringSliceVar(&impl.mavenRepositories, "maven-repository", nil, "Add a maven repository")
+ cmd.Flags().String("local-repository", "", "Location of the local maven repository")
+ cmd.Flags().String("maven-settings", "", "Configure the source of the maven settings (configmap|secret:name[/key])")
+ cmd.Flags().StringArray("maven-repository", nil, "Add a maven repository")
// completion support
configureBashAnnotationForFlag(
@@ -103,40 +112,41 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
type installCmdOptions struct {
*RootCmdOptions
- wait bool
- clusterSetupOnly bool
- skipOperatorSetup bool
- skipClusterSetup bool
- exampleSetup bool
- global bool
- kanikoBuildCache bool
- clusterType string
- outputFormat string
- camelVersion string
- runtimeVersion string
- baseImage string
- operatorImage string
- localRepository string
- buildStrategy string
- buildTimeout string
- mavenRepositories []string
- mavenSettings string
- properties []string
- kits []string
- registry v1alpha1.IntegrationPlatformRegistrySpec
- registryAuth registry.Auth
- traitProfile string
- httpProxySecret string
+ Wait bool `mapstructure:"wait"`
+ ClusterSetupOnly bool `mapstructure:"cluster-setup"`
+ SkipOperatorSetup bool `mapstructure:"skip-operator-setup"`
+ SkipClusterSetup bool `mapstructure:"skip-cluster-setup"`
+ ExampleSetup bool `mapstructure:"example"`
+ Global bool `mapstructure:"global"`
+ KanikoBuildCache bool `mapstructure:"kaniko-build-cache"`
+ ClusterType string `mapstructure:"cluster-type"`
+ OutputFormat string `mapstructure:"output"`
+ CamelVersion string `mapstructure:"camel-version"`
+ RuntimeVersion string `mapstructure:"runtime-version"`
+ BaseImage string `mapstructure:"base-image"`
+ OperatorImage string `mapstructure:"operator-image"`
+ LocalRepository string `mapstructure:"local-repository"`
+ BuildStrategy string `mapstructure:"build-strategy"`
+ BuildTimeout string `mapstructure:"build-timeout"`
+ MavenRepositories []string `mapstructure:"maven-repositories"`
+ MavenSettings string `mapstructure:"maven-settings"`
+ Properties []string `mapstructure:"properties"`
+ Kits []string `mapstructure:"kits"`
+ TraitProfile string `mapstructure:"trait-profile"`
+ HTTPProxySecret string `mapstructure:"http-proxy-secret"`
+
+ registry v1alpha1.IntegrationPlatformRegistrySpec
+ registryAuth registry.Auth
}
// nolint: gocyclo
-func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
+func (o *installCmdOptions) install(_ *cobra.Command, _ []string) error {
var collection *kubernetes.Collection
- if o.outputFormat != "" {
+ if o.OutputFormat != "" {
collection = kubernetes.NewCollection()
}
- if !o.skipClusterSetup {
+ if !o.SkipClusterSetup {
// Let's use a client provider during cluster installation, to eliminate the problem of CRD object caching
clientProvider := client.Provider{Get: o.NewCmdClient}
@@ -151,7 +161,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
}
}
- if o.clusterSetupOnly {
+ if o.ClusterSetupOnly {
if collection == nil {
fmt.Println("Camel K cluster setup completed successfully")
}
@@ -163,12 +173,12 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
namespace := o.Namespace
- if !o.skipOperatorSetup {
+ if !o.SkipOperatorSetup {
cfg := install.OperatorConfiguration{
- CustomImage: o.operatorImage,
+ CustomImage: o.OperatorImage,
Namespace: namespace,
- Global: o.global,
- ClusterType: o.clusterType,
+ Global: o.Global,
+ ClusterType: o.ClusterType,
}
err = install.OperatorOrCollect(o.Context, c, cfg, collection)
if err != nil {
@@ -188,7 +198,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
}
}
- platform, err := install.PlatformOrCollect(o.Context, c, o.clusterType, namespace, o.registry, collection)
+ platform, err := install.PlatformOrCollect(o.Context, c, o.ClusterType, namespace, o.registry, collection)
if err != nil {
return err
}
@@ -197,10 +207,10 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
platform.Spec.Build.Registry.Secret = generatedSecretName
}
- if len(o.properties) > 0 {
+ if len(o.Properties) > 0 {
platform.Spec.Build.Properties = make(map[string]string)
- for _, property := range o.properties {
+ for _, property := range o.Properties {
kv := strings.Split(property, "=")
if len(kv) == 2 {
@@ -208,20 +218,20 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
}
}
}
- if o.localRepository != "" {
- platform.Spec.Build.Maven.LocalRepository = o.localRepository
+ if o.LocalRepository != "" {
+ platform.Spec.Build.Maven.LocalRepository = o.LocalRepository
}
- if o.camelVersion != "" {
- platform.Spec.Build.CamelVersion = o.camelVersion
+ if o.CamelVersion != "" {
+ platform.Spec.Build.CamelVersion = o.CamelVersion
}
- if o.runtimeVersion != "" {
- platform.Spec.Build.RuntimeVersion = o.runtimeVersion
+ if o.RuntimeVersion != "" {
+ platform.Spec.Build.RuntimeVersion = o.RuntimeVersion
}
- if o.baseImage != "" {
- platform.Spec.Build.BaseImage = o.baseImage
+ if o.BaseImage != "" {
+ platform.Spec.Build.BaseImage = o.BaseImage
}
- if o.buildStrategy != "" {
- switch s := o.buildStrategy; s {
+ if o.BuildStrategy != "" {
+ switch s := o.BuildStrategy; s {
case v1alpha1.IntegrationPlatformBuildStrategyPod:
platform.Spec.Build.BuildStrategy = v1alpha1.IntegrationPlatformBuildStrategyPod
case v1alpha1.IntegrationPlatformBuildStrategyRoutine:
@@ -230,8 +240,8 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
return fmt.Errorf("unknown build strategy: %s", s)
}
}
- if o.buildTimeout != "" {
- d, err := time.ParseDuration(o.buildTimeout)
+ if o.BuildTimeout != "" {
+ d, err := time.ParseDuration(o.BuildTimeout)
if err != nil {
return err
}
@@ -240,54 +250,52 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
Duration: d,
}
}
- if o.traitProfile != "" {
- platform.Spec.Profile = v1alpha1.TraitProfileByName(o.traitProfile)
+ if o.TraitProfile != "" {
+ platform.Spec.Profile = v1alpha1.TraitProfileByName(o.TraitProfile)
}
- if len(o.mavenRepositories) > 0 {
- for _, r := range o.mavenRepositories {
+ if len(o.MavenRepositories) > 0 {
+ for _, r := range o.MavenRepositories {
platform.AddConfiguration("repository", r)
}
}
- if o.mavenSettings != "" {
- mavenSettings, err := decodeMavenSettings(o.mavenSettings)
+ if o.MavenSettings != "" {
+ mavenSettings, err := decodeMavenSettings(o.MavenSettings)
if err != nil {
return err
}
platform.Spec.Build.Maven.Settings = mavenSettings
}
- if o.httpProxySecret != "" {
- platform.Spec.Build.HTTPProxySecret = o.httpProxySecret
+ if o.HTTPProxySecret != "" {
+ platform.Spec.Build.HTTPProxySecret = o.HTTPProxySecret
}
- if o.clusterType != "" {
+ if o.ClusterType != "" {
for _, c := range v1alpha1.AllIntegrationPlatformClusters {
- if strings.EqualFold(string(c), o.clusterType) {
+ if strings.EqualFold(string(c), o.ClusterType) {
platform.Spec.Cluster = c
}
}
}
- kanikoBuildCacheFlag := cobraCmd.Flags().Lookup("kaniko-build-cache")
-
- if kanikoBuildCacheFlag.Changed {
- platform.Spec.Build.KanikoBuildCache = &o.kanikoBuildCache
+ if !o.KanikoBuildCache {
+ platform.Spec.Build.KanikoBuildCache = &o.KanikoBuildCache
}
- platform.Spec.Resources.Kits = o.kits
+ platform.Spec.Resources.Kits = o.Kits
// Do not create an integration platform in global mode as platforms are expected
// to be created in other namespaces
- if !o.global {
+ if !o.Global {
err = install.RuntimeObjectOrCollect(o.Context, c, namespace, collection, platform)
if err != nil {
return err
}
}
- if o.exampleSetup {
+ if o.ExampleSetup {
err = install.ExampleOrCollect(o.Context, c, namespace, collection)
if err != nil {
return err
@@ -295,14 +303,14 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
}
if collection == nil {
- if o.wait {
+ if o.Wait {
err = o.waitForPlatformReady(platform)
if err != nil {
return err
}
}
- if o.global {
+ if o.Global {
fmt.Println("Camel K installed in namespace", namespace, "(global mode)")
} else {
fmt.Println("Camel K installed in namespace", namespace)
@@ -319,7 +327,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) error {
lst := collection.AsKubernetesList()
- switch o.outputFormat {
+ switch o.OutputFormat {
case "yaml":
data, err := kubernetes.ToYAML(lst)
if err != nil {
@@ -333,7 +341,7 @@ func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) error
}
fmt.Print(string(data))
default:
- return errors.New("unknown output format: " + o.outputFormat)
+ return errors.New("unknown output format: " + o.OutputFormat)
}
return nil
}
@@ -360,6 +368,23 @@ func (o *installCmdOptions) waitForPlatformReady(platform *v1alpha1.IntegrationP
return watch.HandlePlatformStateChanges(o.Context, platform, handler)
}
+func (o *installCmdOptions) decode(cmd *cobra.Command, _ []string) error {
+ path := pathToRoot(cmd)
+ if err := decodeKey(o, path); err != nil {
+ return err
+ }
+
+ o.registry.Address = viper.GetString(path + ".registry")
+ o.registry.Organization = viper.GetString(path + ".organization")
+ o.registry.Secret = viper.GetString(path + ".registry-secret")
+ o.registry.Insecure = viper.GetBool(path + ".registry-insecure")
+ o.registryAuth.Username = viper.GetString(path + ".registry-auth-username")
+ o.registryAuth.Password = viper.GetString(path + ".registry-auth-password")
+ o.registryAuth.Server = viper.GetString(path + ".registry-auth-server")
+
+ return nil
+}
+
func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
var result error
@@ -369,20 +394,20 @@ func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
return err
}
- for _, kit := range o.kits {
+ for _, kit := range o.Kits {
err := errorIfKitIsNotAvailable(schema, kit)
result = multierr.Append(result, err)
}
- if len(o.mavenRepositories) > 0 && o.mavenSettings != "" {
+ if len(o.MavenRepositories) > 0 && o.MavenSettings != "" {
err := fmt.Errorf("incompatible options combinations: you cannot set both mavenRepository and mavenSettings")
result = multierr.Append(result, err)
}
- if o.traitProfile != "" {
- tp := v1alpha1.TraitProfileByName(o.traitProfile)
+ if o.TraitProfile != "" {
+ tp := v1alpha1.TraitProfileByName(o.TraitProfile)
if tp == v1alpha1.TraitProfile("") {
- err := fmt.Errorf("unknown trait profile %s", o.traitProfile)
+ err := fmt.Errorf("unknown trait profile %s", o.TraitProfile)
result = multierr.Append(result, err)
}
}
diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go
index f9475ef..3f66c2f 100644
--- a/pkg/cmd/kit_create.go
+++ b/pkg/cmd/kit_create.go
@@ -22,14 +22,13 @@ import (
"fmt"
"strings"
+ "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/apache/camel-k/pkg/trait"
-
"github.com/apache/camel-k/pkg/util"
-
- "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/apache/camel-k/pkg/util/kubernetes"
"github.com/spf13/cobra"
+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -40,20 +39,21 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "create <name>",
- Short: "Create an Integration Kit",
- Long: `Create an Integration Kit.`,
- Args: impl.validateArgs,
- RunE: impl.run,
- }
-
- cmd.Flags().StringVar(&impl.image, "image", "", "Image used to create the kit")
- cmd.Flags().StringSliceVarP(&impl.dependencies, "dependency", "d", nil, "Add a dependency")
- cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property")
- cmd.Flags().StringSliceVar(&impl.configmaps, "configmap", nil, "Add a ConfigMap")
- cmd.Flags().StringSliceVar(&impl.secrets, "secret", nil, "Add a Secret")
- cmd.Flags().StringSliceVar(&impl.repositories, "repository", nil, "Add a maven repository")
- cmd.Flags().StringSliceVarP(&impl.traits, "trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
+ Use: "create <name>",
+ Short: "Create an Integration Kit",
+ Long: `Create an Integration Kit.`,
+ Args: impl.validateArgs,
+ PreRunE: decode(impl),
+ RunE: impl.run,
+ }
+
+ cmd.Flags().String("image", "", "Image used to create the kit")
+ cmd.Flags().StringArrayP("dependency", "d", nil, "Add a dependency")
+ cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+ cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+ cmd.Flags().StringArray("secret", nil, "Add a Secret")
+ cmd.Flags().StringArray("repository", nil, "Add a maven repository")
+ cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
// completion support
configureKnownCompletions(&cmd)
@@ -64,13 +64,13 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
type kitCreateCommand struct {
*RootCmdOptions
- image string
- dependencies []string
- properties []string
- configmaps []string
- secrets []string
- repositories []string
- traits []string
+ Image string `mapstructure:"image"`
+ Dependencies []string `mapstructure:"dependencies"`
+ Properties []string `mapstructure:"properties"`
+ Configmaps []string `mapstructure:"configmaps"`
+ Secrets []string `mapstructure:"secrets"`
+ Repositories []string `mapstructure:"repositories"`
+ Traits []string `mapstructure:"traits"`
}
func (command *kitCreateCommand) validateArgs(_ *cobra.Command, args []string) error {
@@ -89,7 +89,7 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
catalog := trait.NewCatalog(command.Context, c)
tp := catalog.ComputeTraitsProperties()
- for _, t := range command.traits {
+ for _, t := range command.Traits {
kv := strings.SplitN(t, "=", 2)
if !util.StringSliceExists(tp, kv[0]) {
@@ -118,25 +118,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
"camel.apache.org/kit.type": v1alpha1.IntegrationKitTypeUser,
}
ctx.Spec = v1alpha1.IntegrationKitSpec{
- Dependencies: make([]string, 0, len(command.dependencies)),
+ Dependencies: make([]string, 0, len(command.Dependencies)),
Configuration: make([]v1alpha1.ConfigurationSpec, 0),
- Repositories: command.repositories,
+ Repositories: command.Repositories,
}
- if command.image != "" {
+ if command.Image != "" {
//
- // if the image is set, the kit do not require any build but
+ // if the Image is set, the kit do not require any build but
// is be marked as external as the information about the classpath
- // is missing so it cannot be used as base for other kits
+ // is missing so it cannot be used as base for other Kits
//
ctx.Labels["camel.apache.org/kit.type"] = v1alpha1.IntegrationKitTypeExternal
//
- // Set the image to be used by the kit
+ // Set the Image to be used by the kit
//
- ctx.Spec.Image = command.image
+ ctx.Spec.Image = command.Image
}
- for _, item := range command.dependencies {
+ for _, item := range command.Dependencies {
switch {
case strings.HasPrefix(item, "mvn:"):
ctx.Spec.Dependencies = append(ctx.Spec.Dependencies, item)
@@ -149,25 +149,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
}
}
- for _, item := range command.properties {
+ for _, item := range command.Properties {
ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
Type: "property",
Value: item,
})
}
- for _, item := range command.configmaps {
+ for _, item := range command.Configmaps {
ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
Type: "configmap",
Value: item,
})
}
- for _, item := range command.secrets {
+ for _, item := range command.Secrets {
ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
Type: "secret",
Value: item,
})
}
- for _, item := range command.traits {
+ for _, item := range command.Traits {
if err := command.configureTrait(&ctx, item); err != nil {
return nil
}
diff --git a/pkg/cmd/kit_delete.go b/pkg/cmd/kit_delete.go
index 0d24172..7902fae 100644
--- a/pkg/cmd/kit_delete.go
+++ b/pkg/cmd/kit_delete.go
@@ -35,9 +35,10 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "delete",
- Short: "Delete an Integration Kit",
- Long: `Delete an Integration Kit.`,
+ Use: "delete",
+ Short: "Delete an Integration Kit",
+ Long: `Delete an Integration Kit.`,
+ PreRunE: decode(&impl),
RunE: func(_ *cobra.Command, args []string) error {
if err := impl.validate(args); err != nil {
return err
@@ -50,22 +51,22 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
},
}
- cmd.Flags().BoolVar(&impl.all, "all", false, "Delete all integration kits")
+ cmd.Flags().Bool("all", false, "Delete all integration Kits")
return &cmd
}
type kitDeleteCommand struct {
*RootCmdOptions
- all bool
+ All bool `mapstructure:"all"`
}
func (command *kitDeleteCommand) validate(args []string) error {
- if command.all && len(args) > 0 {
- return errors.New("invalid combination: both all flag and named kits are set")
+ if command.All && len(args) > 0 {
+ return errors.New("invalid combination: both all flag and named Kits are set")
}
- if !command.all && len(args) == 0 {
- return errors.New("invalid combination: neither all flag nor named kits are set")
+ if !command.All && len(args) == 0 {
+ return errors.New("invalid combination: neither all flag nor named Kits are set")
}
return nil
@@ -79,7 +80,7 @@ func (command *kitDeleteCommand) run(args []string) error {
return err
}
- if command.all {
+ if command.All {
kitList := v1alpha1.NewIntegrationKitList()
if err := c.List(command.Context, &kitList, k8sclient.InNamespace(command.Namespace)); err != nil {
return err
@@ -87,7 +88,7 @@ func (command *kitDeleteCommand) run(args []string) error {
names = make([]string, 0, len(kitList.Items))
for _, item := range kitList.Items {
- // only include non platform kits
+ // only include non platform Kits
if item.Labels["camel.apache.org/kit.type"] != v1alpha1.IntegrationKitTypePlatform {
names = append(names, item.Name)
}
@@ -129,8 +130,8 @@ func (command *kitDeleteCommand) delete(name string) error {
// check that it is not a platform one which is supposed to be "read only"
// thus not managed by the end user
if ctx.Labels["camel.apache.org/kit.type"] == v1alpha1.IntegrationKitTypePlatform {
- // skip platform kits while deleting all kits
- if command.all {
+ // skip platform Kits while deleting all Kits
+ if command.All {
return nil
}
diff --git a/pkg/cmd/kit_get.go b/pkg/cmd/kit_get.go
index 9d7f109..a22af7b 100644
--- a/pkg/cmd/kit_get.go
+++ b/pkg/cmd/kit_get.go
@@ -34,9 +34,10 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "get",
- Short: "Get defined Integration Kit",
- Long: `Get defined Integration Kit.`,
+ Use: "get",
+ Short: "Get defined Integration Kit",
+ Long: `Get defined Integration Kit.`,
+ PreRunE: decode(&impl),
RunE: func(cmd *cobra.Command, args []string) error {
if err := impl.validate(cmd, args); err != nil {
return err
@@ -49,18 +50,18 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
},
}
- cmd.Flags().BoolVar(&impl.user, v1alpha1.IntegrationKitTypeUser, true, "Includes user kits")
- cmd.Flags().BoolVar(&impl.external, v1alpha1.IntegrationKitTypeExternal, true, "Includes external kits")
- cmd.Flags().BoolVar(&impl.platform, v1alpha1.IntegrationKitTypePlatform, true, "Includes platform kits")
+ cmd.Flags().Bool(v1alpha1.IntegrationKitTypeUser, true, "Includes user Kits")
+ cmd.Flags().Bool(v1alpha1.IntegrationKitTypeExternal, true, "Includes external Kits")
+ cmd.Flags().Bool(v1alpha1.IntegrationKitTypePlatform, true, "Includes platform Kits")
return &cmd
}
type kitGetCommand struct {
*RootCmdOptions
- user bool
- external bool
- platform bool
+ User bool `mapstructure:"user"`
+ External bool `mapstructure:"external"`
+ Platform bool `mapstructure:"platform"`
}
func (command *kitGetCommand) validate(cmd *cobra.Command, args []string) error {
@@ -81,9 +82,9 @@ func (command *kitGetCommand) run(cmd *cobra.Command) error {
fmt.Fprintln(w, "NAME\tPHASE\tTYPE\tIMAGE")
for _, ctx := range kitList.Items {
t := ctx.Labels["camel.apache.org/kit.type"]
- u := command.user && t == v1alpha1.IntegrationKitTypeUser
- e := command.external && t == v1alpha1.IntegrationKitTypeExternal
- p := command.platform && t == v1alpha1.IntegrationKitTypePlatform
+ u := command.User && t == v1alpha1.IntegrationKitTypeUser
+ e := command.External && t == v1alpha1.IntegrationKitTypeExternal
+ p := command.Platform && t == v1alpha1.IntegrationKitTypePlatform
if u || e || p {
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ctx.Name, string(ctx.Status.Phase), t, ctx.Status.Image)
diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go
index 151c8aa..852c9c3 100644
--- a/pkg/cmd/log.go
+++ b/pkg/cmd/log.go
@@ -33,11 +33,12 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "log integration",
- Short: "Print the logs of an integration",
- Long: `Print the logs of an integration.`,
- Args: options.validate,
- RunE: options.run,
+ Use: "log integration",
+ Short: "Print the logs of an integration",
+ Long: `Print the logs of an integration.`,
+ Args: options.validate,
+ PreRunE: decode(&options),
+ RunE: options.run,
}
// completion support
@@ -85,7 +86,7 @@ func (o *logCmdOptions) run(cmd *cobra.Command, args []string) error {
return err
}
- // Let's add a wait point, otherwise the script terminates
+ // Let's add a Wait point, otherwise the script terminates
<-o.Context.Done()
return nil
diff --git a/pkg/cmd/operator.go b/pkg/cmd/operator.go
index a1a70c2..87361fd 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/operator.go
@@ -22,25 +22,16 @@ import (
"github.com/spf13/cobra"
)
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
- impl := operatorCmdOptions{
- RootCmdOptions: rootCmdOptions,
- }
+func newCmdOperator() *cobra.Command {
cmd := cobra.Command{
Use: "operator",
Short: "Run the Camel K operator",
Long: `Run the Camel K operator`,
Hidden: true,
- Run: impl.run,
+ Run: func(cmd *cobra.Command, args []string) {
+ operator.Run()
+ },
}
return &cmd
}
-
-type operatorCmdOptions struct {
- *RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
- operator.Run()
-}
diff --git a/pkg/cmd/rebuild.go b/pkg/cmd/rebuild.go
index c906b90..d88738a 100644
--- a/pkg/cmd/rebuild.go
+++ b/pkg/cmd/rebuild.go
@@ -34,10 +34,11 @@ func newCmdRebuild(rootCmdOptions *RootCmdOptions) *cobra.Command {
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
- Use: "rebuild [integration]",
- Short: "Clear the state of integrations to rebuild them",
- Long: `Clear the state of one or more integrations causing a rebuild.`,
- RunE: options.rebuild,
+ Use: "rebuild [integration]",
+ Short: "Clear the state of integrations to rebuild them",
+ Long: `Clear the state of one or more integrations causing a rebuild.`,
+ PreRunE: decode(&options),
+ RunE: options.rebuild,
}
return &cmd
diff --git a/pkg/cmd/reset.go b/pkg/cmd/reset.go
index ff9c86d..02bd058 100644
--- a/pkg/cmd/reset.go
+++ b/pkg/cmd/reset.go
@@ -34,22 +34,23 @@ func newCmdReset(rootCmdOptions *RootCmdOptions) *cobra.Command {
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
- Use: "reset",
- Short: "Reset the Camel K installation",
- Long: `Reset the Camel K installation by deleting everything except current platform configuration.`,
- Run: options.reset,
+ Use: "reset",
+ Short: "Reset the Camel K installation",
+ Long: `Reset the Camel K installation by deleting everything except current platform configuration.`,
+ PreRunE: decode(&options),
+ Run: options.reset,
}
- cmd.Flags().BoolVar(&options.SkipKits, "skip-kits", false, "Do not delete the integration kits")
- cmd.Flags().BoolVar(&options.SkipIntegrations, "skip-integrations", false, "Do not delete the integrations")
+ cmd.Flags().Bool("skip-kits", false, "Do not delete the integration kits")
+ cmd.Flags().Bool("skip-integrations", false, "Do not delete the integrations")
return &cmd
}
type resetCmdOptions struct {
*RootCmdOptions
- SkipKits bool
- SkipIntegrations bool
+ SkipKits bool `mapstructure:"skip-kits"`
+ SkipIntegrations bool `mapstructure:"skip-integrations"`
}
func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) {
@@ -73,7 +74,7 @@ func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) {
fmt.Print(err)
return
}
- fmt.Printf("%d integration kits deleted from namespace %s\n", n, o.Namespace)
+ fmt.Printf("%d integration Kits deleted from namespace %s\n", n, o.Namespace)
}
if err = o.resetIntegrationPlatform(c); err != nil {
@@ -101,7 +102,7 @@ func (o *resetCmdOptions) deleteAllIntegrations(c client.Client) (int, error) {
func (o *resetCmdOptions) deleteAllIntegrationKits(c client.Client) (int, error) {
list := v1alpha1.NewIntegrationKitList()
if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); err != nil {
- return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve integration kits from namespace %s", o.Namespace))
+ return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve integration Kits from namespace %s", o.Namespace))
}
for _, i := range list.Items {
kit := i
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index c5b9168..bbf7acc 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -20,6 +20,9 @@ package cmd
import (
"context"
"os"
+ "strings"
+
+ "github.com/spf13/viper"
"github.com/apache/camel-k/pkg/client"
"github.com/pkg/errors"
@@ -32,10 +35,10 @@ superpowers.
// RootCmdOptions --
type RootCmdOptions struct {
- Context context.Context
- _client client.Client
- KubeConfig string
- Namespace string
+ Context context.Context `mapstructure:"-"`
+ _client client.Client `mapstructure:"-"`
+ KubeConfig string `mapstructure:"kube-config"`
+ Namespace string `mapstructure:"namespace"`
}
// NewKamelCommand --
@@ -65,9 +68,31 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
cmd.AddCommand(newCmdReset(&options))
cmd.AddCommand(newCmdDescribe(&options))
cmd.AddCommand(newCmdRebuild(&options))
- cmd.AddCommand(newCmdOperator(&options))
+ cmd.AddCommand(newCmdOperator())
cmd.AddCommand(newCmdBuilder(&options))
+ bindPFlagsHierarchy(&cmd)
+
+ configName := os.Getenv("KAMEL_CONFIG_NAME")
+ if configName != "" {
+ configName = "config"
+ }
+
+ viper.SetConfigName(configName)
+ viper.AddConfigPath(".kamel")
+ viper.AddConfigPath("$HOME/.kamel")
+ viper.AutomaticEnv()
+ viper.SetEnvKeyReplacer(strings.NewReplacer(
+ ".", "_",
+ "-", "_",
+ ))
+
+ if err := viper.ReadInConfig(); err != nil {
+ if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+ return nil, err
+ }
+ }
+
return &cmd, nil
}
diff --git a/pkg/cmd/operator.go b/pkg/cmd/root_test.go
similarity index 59%
copy from pkg/cmd/operator.go
copy to pkg/cmd/root_test.go
index a1a70c2..57f6621 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/root_test.go
@@ -17,30 +17,7 @@ limitations under the License.
package cmd
-import (
- "github.com/apache/camel-k/pkg/cmd/operator"
- "github.com/spf13/cobra"
-)
+import "testing"
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
- impl := operatorCmdOptions{
- RootCmdOptions: rootCmdOptions,
- }
- cmd := cobra.Command{
- Use: "operator",
- Short: "Run the Camel K operator",
- Long: `Run the Camel K operator`,
- Hidden: true,
- Run: impl.run,
- }
-
- return &cmd
-}
-
-type operatorCmdOptions struct {
- *RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
- operator.Run()
+func TestDecodeRoot(t *testing.T) {
}
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 31b411c..4c41081 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -40,8 +40,10 @@ import (
k8slog "github.com/apache/camel-k/pkg/util/kubernetes/log"
"github.com/apache/camel-k/pkg/util/sync"
"github.com/apache/camel-k/pkg/util/watch"
+
"github.com/pkg/errors"
"github.com/spf13/cobra"
+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -57,34 +59,34 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
}
cmd := cobra.Command{
- Use: "run [file to run]",
- Short: "Run a integration on Kubernetes",
- Long: `Deploys and execute a integration pod on Kubernetes.`,
- Args: options.validateArgs,
- RunE: options.run,
- }
-
- cmd.Flags().StringVar(&options.IntegrationName, "name", "", "The integration name")
- cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency")
- cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the integration to be running")
- cmd.Flags().StringVarP(&options.IntegrationKit, "kit", "k", "", "The kit used to run the integration")
- cmd.Flags().StringArrayVarP(&options.Properties, "property", "p", nil, "Add a camel property")
- cmd.Flags().StringSliceVar(&options.ConfigMaps, "configmap", nil, "Add a ConfigMap")
- cmd.Flags().StringSliceVar(&options.Secrets, "secret", nil, "Add a Secret")
- cmd.Flags().StringSliceVar(&options.Repositories, "repository", nil, "Add a maven repository")
- cmd.Flags().BoolVar(&options.Logs, "logs", false, "Print integration logs")
- cmd.Flags().BoolVar(&options.Sync, "sync", false, "Synchronize the local source file with the cluster, republishing at each change")
- cmd.Flags().BoolVar(&options.Dev, "dev", false, "Enable Dev mode (equivalent to \"-w --logs --sync\")")
- cmd.Flags().StringVar(&options.Profile, "profile", "", "Trait profile used for deployment")
- cmd.Flags().StringSliceVarP(&options.Traits, "trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
- cmd.Flags().StringSliceVar(&options.LoggingLevels, "logging-level", nil, "Configure the logging level. "+
- "E.g. \"--logging-level org.apache.camel=DEBUG\"")
- cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", "", "Output format. One of: json|yaml")
- cmd.Flags().BoolVar(&options.Compression, "compression", false, "Enable store source as a compressed binary blob")
- cmd.Flags().StringSliceVar(&options.Resources, "resource", nil, "Add a resource")
- cmd.Flags().StringSliceVar(&options.OpenAPIs, "open-api", nil, "Add an OpenAPI v2 spec")
- cmd.Flags().StringSliceVarP(&options.Volumes, "volume", "v", nil, "Mount a volume into the integration container. E.g \"-v pvcname:/container/path\"")
- cmd.Flags().StringSliceVarP(&options.EnvVars, "env", "e", nil, "Set an environment variable in the integration container. E.g \"-e MY_VAR=my-value\"")
+ Use: "run [file to run]",
+ Short: "Run a integration on Kubernetes",
+ Long: `Deploys and execute a integration pod on Kubernetes.`,
+ Args: options.validateArgs,
+ PreRunE: decode(&options),
+ RunE: options.run,
+ }
+
+ cmd.Flags().String("name", "", "The integration name")
+ cmd.Flags().StringArrayP("dependency", "d", nil, "The integration dependency")
+ cmd.Flags().BoolP("wait", "w", false, "Waits for the integration to be running")
+ cmd.Flags().StringP("kit", "k", "", "The kit used to run the integration")
+ cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+ cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+ cmd.Flags().StringArray("secret", nil, "Add a Secret")
+ cmd.Flags().StringArray("maven-repository", nil, "Add a maven repository")
+ cmd.Flags().Bool("logs", false, "Print integration logs")
+ cmd.Flags().Bool("sync", false, "Synchronize the local source file with the cluster, republishing at each change")
+ cmd.Flags().Bool("dev", false, "Enable Dev mode (equivalent to \"-w --logs --sync\")")
+ cmd.Flags().String("profile", "", "Trait profile used for deployment")
+ cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
+ cmd.Flags().StringArray("logging-level", nil, "Configure the logging level. e.g. \"--logging-level org.apache.camel=DEBUG\"")
+ cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
+ cmd.Flags().Bool("compression", false, "Enable store source as a compressed binary blob")
+ cmd.Flags().StringArray("resource", nil, "Add a resource")
+ cmd.Flags().StringArray("open-api", nil, "Add an OpenAPI v2 spec")
+ cmd.Flags().StringArrayP("volume", "v", nil, "Mount a volume into the integration container. E.g \"-v pvcname:/container/path\"")
+ cmd.Flags().StringArrayP("env", "e", nil, "Set an environment variable in the integration container. E.g \"-e MY_VAR=my-value\"")
// completion support
configureKnownCompletions(&cmd)
@@ -94,26 +96,26 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
type runCmdOptions struct {
*RootCmdOptions
- Compression bool
- Wait bool
- Logs bool
- Sync bool
- Dev bool
- IntegrationKit string
- IntegrationName string
- Profile string
- OutputFormat string
- Resources []string
- OpenAPIs []string
- Dependencies []string
- Properties []string
- ConfigMaps []string
- Secrets []string
- Repositories []string
- Traits []string
- LoggingLevels []string
- Volumes []string
- EnvVars []string
+ Compression bool `mapstructure:"compression"`
+ Wait bool `mapstructure:"wait"`
+ Logs bool `mapstructure:"logs"`
+ Sync bool `mapstructure:"sync"`
+ Dev bool `mapstructure:"dev"`
+ IntegrationKit string `mapstructure:"kit"`
+ IntegrationName string `mapstructure:"name"`
+ Profile string `mapstructure:"profile"`
+ OutputFormat string `mapstructure:"output"`
+ Resources []string `mapstructure:"resources"`
+ OpenAPIs []string `mapstructure:"open-apis"`
+ Dependencies []string `mapstructure:"dependencies"`
+ Properties []string `mapstructure:"properties"`
+ ConfigMaps []string `mapstructure:"configmaps"`
+ Secrets []string `mapstructure:"secrets"`
+ Repositories []string `mapstructure:"maven-repositories"`
+ Traits []string `mapstructure:"traits"`
+ LoggingLevels []string `mapstructure:"logging-levels"`
+ Volumes []string `mapstructure:"volumes"`
+ EnvVars []string `mapstructure:"envs"`
}
func (o *runCmdOptions) validateArgs(_ *cobra.Command, args []string) error {
@@ -232,7 +234,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
}
if o.Sync && !o.Logs && !o.Dev {
- // Let's add a wait point, otherwise the script terminates
+ // Let's add a Wait point, otherwise the script terminates
<-o.Context.Done()
}
return nil
@@ -241,7 +243,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
func (o *runCmdOptions) waitForIntegrationReady(integration *v1alpha1.Integration) (*v1alpha1.IntegrationPhase, error) {
handler := func(i *v1alpha1.Integration) bool {
//
- // TODO when we add health checks, we should wait until they are passed
+ // TODO when we add health checks, we should Wait until they are passed
//
if i.Status.Phase != "" {
fmt.Println("integration \""+integration.Name+"\" in phase", i.Status.Phase)
diff --git a/pkg/cmd/util.go b/pkg/cmd/util.go
index d6cb4ee..a32dcce 100644
--- a/pkg/cmd/util.go
+++ b/pkg/cmd/util.go
@@ -19,9 +19,21 @@ package cmd
import (
"context"
+ "encoding/csv"
+ "fmt"
+ "log"
+ "reflect"
+ "strings"
+
+ "github.com/mitchellh/mapstructure"
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/apache/camel-k/pkg/client"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+ "github.com/spf13/viper"
+
+ p "github.com/gertd/go-pluralize"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -39,3 +51,135 @@ func DeleteIntegration(ctx context.Context, c client.Client, name string, namesp
}
return c.Delete(ctx, &integration)
}
+
+func bindPFlagsHierarchy(cmd *cobra.Command) error {
+ for _, c := range cmd.Commands() {
+ if err := bindPFlags(c); err != nil {
+ return err
+ }
+
+ if err := bindPFlagsHierarchy(c); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func bindPFlags(cmd *cobra.Command) error {
+ prefix := pathToRoot(cmd)
+ pl := p.NewClient()
+
+ cmd.Flags().VisitAll(func(flag *pflag.Flag) {
+ name := flag.Name
+ name = strings.ReplaceAll(name, "_", "-")
+ name = strings.ReplaceAll(name, ".", "-")
+
+ if err := viper.BindPFlag(prefix+"."+name, flag); err != nil {
+ log.Printf("error binding flag %s with prefix %s to viper: %v", flag.Name, prefix, err)
+ }
+
+ // this is a little bit of an hack to register plural version of properties
+ // based on the naming conventions used by the flag type because it is not
+ // possible to know what is the type of a flag
+ flagType := strings.ToUpper(flag.Value.Type())
+ if strings.Contains(flagType, "SLICE") || strings.Contains(flagType, "ARRAY") {
+ if err := viper.BindPFlag(prefix+"."+pl.Plural(name), flag); err != nil {
+ log.Printf("error binding plural flag %s with prefix %s to viper: %v", flag.Name, prefix, err)
+ }
+ }
+ })
+
+ return nil
+}
+
+func pathToRoot(cmd *cobra.Command) string {
+ path := cmd.Name()
+
+ for current := cmd.Parent(); current != nil; current = current.Parent() {
+ name := current.Name()
+ name = strings.ReplaceAll(name, "_", "-")
+ name = strings.ReplaceAll(name, ".", "-")
+ path = name + "." + path
+ }
+
+ return path
+}
+
+func decodeKey(target interface{}, key string) error {
+ nodes := strings.Split(key, ".")
+ settings := viper.AllSettings()
+
+ for _, node := range nodes {
+ v := settings[node]
+
+ if v == nil {
+ return nil
+ }
+
+ if m, ok := v.(map[string]interface{}); ok {
+ settings = m
+ } else {
+ return fmt.Errorf("unable to find node %s", node)
+ }
+ }
+
+ c := mapstructure.DecoderConfig{
+ Result: target,
+ WeaklyTypedInput: true,
+ DecodeHook: mapstructure.ComposeDecodeHookFunc(
+ mapstructure.StringToIPNetHookFunc(),
+ mapstructure.StringToTimeDurationHookFunc(),
+ stringToSliceHookFunc(','),
+ ),
+ }
+
+ decoder, err := mapstructure.NewDecoder(&c)
+ if err != nil {
+ return err
+ }
+
+ err = decoder.Decode(settings)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func decode(target interface{}) func(*cobra.Command, []string) error {
+ return func(cmd *cobra.Command, args []string) error {
+ path := pathToRoot(cmd)
+ if err := decodeKey(target, path); err != nil {
+ return err
+ }
+
+ return nil
+ }
+}
+
+func stringToSliceHookFunc(comma rune) mapstructure.DecodeHookFunc {
+ return func(
+ f reflect.Kind,
+ t reflect.Kind,
+ data interface{}) (interface{}, error) {
+ if f != reflect.String || t != reflect.Slice {
+ return data, nil
+ }
+
+ s := data.(string)
+ s = strings.TrimPrefix(s, "[")
+ s = strings.TrimSuffix(s, "]")
+
+ if s == "" {
+ return []string{}, nil
+ }
+
+ stringReader := strings.NewReader(s)
+ csvReader := csv.NewReader(stringReader)
+ csvReader.Comma = comma
+ csvReader.LazyQuotes = true
+
+ return csvReader.Read()
+ }
+}