Merge "Define a standard for creating commands"

This commit is contained in:
Zuul 2020-04-27 20:41:41 +00:00 committed by Gerrit Code Review
commit bf63997ed6
65 changed files with 835 additions and 600 deletions

View File

@ -20,16 +20,23 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
// NewClusterCommand returns cobra command object of the airshipctl cluster and adds it's subcommands. const (
// TODO: (kkalynovskyi) Add more description when more subcommands are added
clusterLong = `
This command provides capabilities for interacting with a Kubernetes cluster,
such as getting status and deploying initial infrastructure.
`
)
// NewClusterCommand creates a command for interacting with a Kubernetes cluster.
func NewClusterCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewClusterCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
clusterRootCmd := &cobra.Command{ clusterRootCmd := &cobra.Command{
Use: "cluster", Use: "cluster",
// TODO: (kkalynovskyi) Add more description when more subcommands are added Short: "Manage Kubernetes clusters",
Short: "Control Kubernetes cluster", Long: clusterLong[1:],
Long: "Interactions with Kubernetes cluster, such as get status, deploy initial infrastructure",
} }
clusterRootCmd.AddCommand(NewCmdInitInfra(rootSettings)) clusterRootCmd.AddCommand(NewInitInfraCommand(rootSettings))
return clusterRootCmd return clusterRootCmd
} }

View File

@ -22,7 +22,7 @@ import (
"opendev.org/airship/airshipctl/testutil" "opendev.org/airship/airshipctl/testutil"
) )
func TestNewClusterCommandReturn(t *testing.T) { func TestNewClusterCommand(t *testing.T) {
fakeRootSettings := &environment.AirshipCTLSettings{ fakeRootSettings := &environment.AirshipCTLSettings{
AirshipConfigPath: "../../testdata/k8s/config.yaml", AirshipConfigPath: "../../testdata/k8s/config.yaml",
KubeConfigPath: "../../testdata/k8s/kubeconfig.yaml", KubeConfigPath: "../../testdata/k8s/kubeconfig.yaml",
@ -31,9 +31,9 @@ func TestNewClusterCommandReturn(t *testing.T) {
tests := []*testutil.CmdTest{ tests := []*testutil.CmdTest{
{ {
Name: "cluster-initinfra-cmd-with-defaults", Name: "cluster-cmd-with-help",
CmdLine: "--help", CmdLine: "--help",
Cmd: cluster.NewCmdInitInfra(fakeRootSettings), Cmd: cluster.NewClusterCommand(fakeRootSettings),
}, },
} }
for _, testcase := range tests { for _, testcase := range tests {

View File

@ -25,20 +25,24 @@ import (
const ( const (
// TODO add labels in description, when we have them designed // TODO add labels in description, when we have them designed
getInitInfraLong = `Deploy initial infrastructure to kubernetes cluster such as ` + initInfraLong = `
`metal3.io, argo, tiller and other manifest documents with appropriate labels` Deploy initial infrastructure to kubernetes cluster such as
getInitInfraExample = `#deploy infra to cluster metal3.io, argo, tiller and other manifest documents with appropriate labels
airshipctl cluster initinfra` `
initInfraExample = `
# Deploy infrastructure to a cluster
airshipctl cluster initinfra
`
) )
// NewCmdInitInfra creates a command to deploy initial airship infrastructure // NewInitInfraCommand creates a command to deploy initial airship infrastructure.
func NewCmdInitInfra(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewInitInfraCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
i := initinfra.NewInfra(rootSettings) i := initinfra.NewInfra(rootSettings)
initinfraCmd := &cobra.Command{ initinfraCmd := &cobra.Command{
Use: "initinfra", Use: "initinfra",
Short: "deploy initinfra components to cluster", Short: "Deploy initinfra components to cluster",
Long: getInitInfraLong, Long: initInfraLong[1:],
Example: getInitInfraExample, Example: initInfraExample,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return i.Run() return i.Run()
}, },
@ -53,19 +57,19 @@ func addInitinfraFlags(i *initinfra.Infra, cmd *cobra.Command) {
&i.DryRun, &i.DryRun,
"dry-run", "dry-run",
false, false,
"Don't deliver documents to the cluster, simulate the changes instead") "don't deliver documents to the cluster, simulate the changes instead")
flags.BoolVar( flags.BoolVar(
&i.Prune, &i.Prune,
"prune", "prune",
false, false,
`If set to true, command will delete all kubernetes resources that are not`+ `if set to true, command will delete all kubernetes resources that are not`+
` defined in airship documents and have airshipit.org/deployed=initinfra label`) ` defined in airship documents and have airshipit.org/deployed=initinfra label`)
flags.StringVar( flags.StringVar(
&i.ClusterType, &i.ClusterType,
"cluster-type", "cluster-type",
"ephemeral", "ephemeral",
`Select cluster type to deploy initial infastructure to;`+ `select cluster type to deploy initial infrastructure to;`+
` currently only ephemeral is supported`) ` currently only ephemeral is supported`)
} }

View File

@ -0,0 +1,42 @@
/*
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
https://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 cluster_test
import (
"testing"
"opendev.org/airship/airshipctl/cmd/cluster"
"opendev.org/airship/airshipctl/pkg/environment"
"opendev.org/airship/airshipctl/testutil"
)
func TestNewInitInfraCommand(t *testing.T) {
fakeRootSettings := &environment.AirshipCTLSettings{
AirshipConfigPath: "../../testdata/k8s/config.yaml",
KubeConfigPath: "../../testdata/k8s/kubeconfig.yaml",
}
fakeRootSettings.InitConfig()
tests := []*testutil.CmdTest{
{
Name: "cluster-initinfra-cmd-with-help",
CmdLine: "--help",
Cmd: cluster.NewInitInfraCommand(fakeRootSettings),
},
}
for _, testcase := range tests {
testutil.RunTest(t, testcase)
}
}

View File

@ -0,0 +1,14 @@
This command provides capabilities for interacting with a Kubernetes cluster,
such as getting status and deploying initial infrastructure.
Usage:
cluster [command]
Available Commands:
help Help about any command
initinfra Deploy initinfra components to cluster
Flags:
-h, --help help for cluster
Use "cluster [command] --help" for more information about a command.

View File

@ -1,14 +0,0 @@
Deploy initial infrastructure to kubernetes cluster such as metal3.io, argo, tiller and other manifest documents with appropriate labels
Usage:
initinfra [flags]
Examples:
#deploy infra to cluster
airshipctl cluster initinfra
Flags:
--cluster-type string Select cluster type to deploy initial infastructure to; currently only ephemeral is supported (default "ephemeral")
--dry-run Don't deliver documents to the cluster, simulate the changes instead
-h, --help help for initinfra
--prune If set to true, command will delete all kubernetes resources that are not defined in airship documents and have airshipit.org/deployed=initinfra label

View File

@ -0,0 +1,17 @@
Deploy initial infrastructure to kubernetes cluster such as
metal3.io, argo, tiller and other manifest documents with appropriate labels
Usage:
initinfra [flags]
Examples:
# Deploy infrastructure to a cluster
airshipctl cluster initinfra
Flags:
--cluster-type string select cluster type to deploy initial infrastructure to; currently only ephemeral is supported (default "ephemeral")
--dry-run don't deliver documents to the cluster, simulate the changes instead
-h, --help help for initinfra
--prune if set to true, command will delete all kubernetes resources that are not defined in airship documents and have airshipit.org/deployed=initinfra label

View File

@ -21,18 +21,20 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const completionDesc = ` const (
Generate autocompletion script for airshipctl for the specified shell (bash or zsh). completionLong = `
Generate completion script for airshipctl for the specified shell (bash or zsh).
This command can generate shell autocompletion. e.g.
$ airshipctl completion bash
Can be sourced as such
$ source <(airshipctl completion bash)
` `
completionExample = `
# Save shell completion to a file
airshipctl completion bash > $HOME/.airship_completions
# Apply completions to the current shell
source <(airshipctl completion bash)
`
)
var ( var (
completionShells = map[string]func(cmd *cobra.Command) error{ completionShells = map[string]func(cmd *cobra.Command) error{
"bash": runCompletionBash, "bash": runCompletionBash,
@ -40,6 +42,7 @@ var (
} }
) )
// NewCompletionCommand creates a cobra command object for generating shell completion scripts.
func NewCompletionCommand() *cobra.Command { func NewCompletionCommand() *cobra.Command {
shells := make([]string, 0, len(completionShells)) shells := make([]string, 0, len(completionShells))
for s := range completionShells { for s := range completionShells {
@ -48,8 +51,9 @@ func NewCompletionCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "completion SHELL", Use: "completion SHELL",
Short: "Generate autocompletions script for the specified shell (bash or zsh)", Short: "Generate completion script for the specified shell (bash or zsh)",
Long: completionDesc, Long: completionLong[1:],
Example: completionExample,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: runCompletion, RunE: runCompletion,
ValidArgs: shells, ValidArgs: shells,

View File

@ -2,6 +2,15 @@ Error: accepts 1 arg(s), received 0
Usage: Usage:
completion SHELL [flags] completion SHELL [flags]
Examples:
# Save shell completion to a file
airshipctl completion bash > $HOME/.airship_completions
# Apply completions to the current shell
source <(airshipctl completion bash)
Flags: Flags:
-h, --help help for completion -h, --help help for completion

View File

@ -2,6 +2,15 @@ Error: accepts 1 arg(s), received 2
Usage: Usage:
completion SHELL [flags] completion SHELL [flags]
Examples:
# Save shell completion to a file
airshipctl completion bash > $HOME/.airship_completions
# Apply completions to the current shell
source <(airshipctl completion bash)
Flags: Flags:
-h, --help help for completion -h, --help help for completion

View File

@ -2,6 +2,15 @@ Error: unsupported shell type "fish"
Usage: Usage:
completion SHELL [flags] completion SHELL [flags]
Examples:
# Save shell completion to a file
airshipctl completion bash > $HOME/.airship_completions
# Apply completions to the current shell
source <(airshipctl completion bash)
Flags: Flags:
-h, --help help for completion -h, --help help for completion

View File

@ -20,23 +20,21 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
// NewConfigCommand creates a command object for the airshipctl "config" , and adds all child commands to it. // NewConfigCommand creates a command for interacting with the airshipctl configuration.
func NewConfigCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewConfigCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
configRootCmd := &cobra.Command{ configRootCmd := &cobra.Command{
Use: "config", Use: "config",
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Short: "Modify airshipctl config files", Short: "Manage the airshipctl config file",
Long: `Modify airshipctl config files using subcommands
like "airshipctl config set-context my-context" `,
} }
configRootCmd.AddCommand(NewCmdConfigSetCluster(rootSettings)) configRootCmd.AddCommand(NewSetClusterCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigGetCluster(rootSettings)) configRootCmd.AddCommand(NewGetClusterCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigSetContext(rootSettings)) configRootCmd.AddCommand(NewSetContextCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigGetContext(rootSettings)) configRootCmd.AddCommand(NewGetContextCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigInit(rootSettings)) configRootCmd.AddCommand(NewInitCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigSetAuthInfo(rootSettings)) configRootCmd.AddCommand(NewSetAuthInfoCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigGetAuthInfo(rootSettings)) configRootCmd.AddCommand(NewGetAuthInfoCommand(rootSettings))
configRootCmd.AddCommand(NewCmdConfigUseContext(rootSettings)) configRootCmd.AddCommand(NewUseContextCommand(rootSettings))
return configRootCmd return configRootCmd
} }

View File

@ -25,24 +25,29 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
getAuthInfoLong = `Display a specific user's information, or all defined users if no name is provided` getAuthInfoLong = `
Display a specific user's credentials, or all defined user
credentials if no name is provided.
`
getAuthInfoExample = `# List all the users airshipctl knows about getAuthInfoExample = `
# List all user credentials
airshipctl config get-credentials airshipctl config get-credentials
# Display a specific user information # Display a specific user's credentials
airshipctl config get-credentials e2e` airshipctl config get-credentials exampleUser
`
) )
// NewCmdConfigGetAuthInfo returns a Command instance for 'config -AuthInfo' sub command // NewGetAuthInfoCommand creates a command for viewing the user credentials
// An AuthInfo refers to a particular user for a cluster // defined in the airshipctl config file.
func NewCmdConfigGetAuthInfo(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewGetAuthInfoCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.AuthInfoOptions{} o := &config.AuthInfoOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get-credentials NAME", Use: "get-credentials [NAME]",
Short: "Gets a user entry from the airshipctl config", Short: "Get user credentials from the airshipctl config",
Long: getAuthInfoLong, Long: getAuthInfoLong[1:],
Example: getAuthInfoExample, Example: getAuthInfoExample,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -47,26 +47,19 @@ func TestGetAuthInfoCmd(t *testing.T) {
} }
cmdTests := []*testutil.CmdTest{ cmdTests := []*testutil.CmdTest{
{
Name: "get-credentials",
CmdLine: fmt.Sprintf("%s", fooAuthInfo),
Cmd: cmd.NewCmdConfigGetAuthInfo(settings),
},
{
Name: "get-all-credentials",
CmdLine: fmt.Sprintf(""),
Cmd: cmd.NewCmdConfigGetAuthInfo(settings),
},
{ {
Name: "get-specific-credentials", Name: "get-specific-credentials",
CmdLine: fmt.Sprintf("%s", fooAuthInfo), CmdLine: fooAuthInfo,
Cmd: cmd.NewCmdConfigGetAuthInfo(settings), Cmd: cmd.NewGetAuthInfoCommand(settings),
},
{
Name: "get-all-credentials",
Cmd: cmd.NewGetAuthInfoCommand(settings),
}, },
{ {
Name: "missing", Name: "missing",
CmdLine: fmt.Sprintf("%s", missingAuthInfo), CmdLine: missingAuthInfo,
Cmd: cmd.NewCmdConfigGetAuthInfo(settings), Cmd: cmd.NewGetAuthInfoCommand(settings),
Error: fmt.Errorf("user %s information was not "+ Error: fmt.Errorf("user %s information was not "+
"found in the configuration", missingAuthInfo), "found in the configuration", missingAuthInfo),
}, },
@ -82,7 +75,7 @@ func TestNoAuthInfosGetAuthInfoCmd(t *testing.T) {
cmdTest := &testutil.CmdTest{ cmdTest := &testutil.CmdTest{
Name: "no-credentials", Name: "no-credentials",
CmdLine: "", CmdLine: "",
Cmd: cmd.NewCmdConfigGetAuthInfo(settings), Cmd: cmd.NewGetAuthInfoCommand(settings),
} }
testutil.RunTest(t, cmdTest) testutil.RunTest(t, cmdTest)
} }

View File

@ -25,23 +25,32 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
getClusterLong = "Display a specific cluster or all defined clusters if no name is provided" getClusterLong = `
Display a specific cluster or all defined clusters if no name is provided.
getClusterExample = fmt.Sprintf(` Note that if a specific cluster's name is provided, the --cluster-type flag
# List all the clusters airshipctl knows about must also be provided.
Valid values for the --cluster-type flag are [ephemeral|target].
`
getClusterExample = `
# List all clusters
airshipctl config get-cluster airshipctl config get-cluster
# Display a specific cluster # Display a specific cluster
airshipctl config get-cluster e2e --%v=ephemeral`, config.FlagClusterType) airshipctl config get-cluster --cluster-type=ephemeral exampleCluster
`
) )
// NewCmdConfigGetCluster returns a Command instance for 'config -Cluster' sub command // NewGetClusterCommand creates a command for viewing the cluster information
func NewCmdConfigGetCluster(rootSettings *environment.AirshipCTLSettings) *cobra.Command { // defined in the airshipctl config file.
func NewGetClusterCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.ClusterOptions{} o := &config.ClusterOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get-cluster NAME", Use: "get-cluster [NAME]",
Short: getClusterLong, Short: "Get cluster information from the airshipctl config",
Long: getClusterLong[1:],
Example: getClusterExample, Example: getClusterExample,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
airconfig := rootSettings.Config airconfig := rootSettings.Config
@ -80,9 +89,9 @@ func addGetClusterFlags(o *config.ClusterOptions, cmd *cobra.Command) {
flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar( flags.StringVar(
&o.ClusterType, &o.ClusterType,
config.FlagClusterType, "cluster-type",
"", "",
config.FlagClusterType+" for the cluster entry in airshipctl config") "type of the desired cluster")
} }
func validate(o *config.ClusterOptions) error { func validate(o *config.ClusterOptions) error {

View File

@ -29,8 +29,8 @@ import (
) )
const ( const (
ephemeralFlag = "--" + config.FlagClusterType + "=" + config.Ephemeral ephemeralFlag = "--cluster-type=ephemeral"
targetFlag = "--" + config.FlagClusterType + "=" + config.Target targetFlag = "--cluster-type=target"
fooCluster = "clusterFoo" fooCluster = "clusterFoo"
barCluster = "clusterBar" barCluster = "clusterBar"
@ -68,12 +68,12 @@ func TestGetClusterCmd(t *testing.T) {
{ {
Name: "get-ephemeral", Name: "get-ephemeral",
CmdLine: fmt.Sprintf("%s %s", ephemeralFlag, fooCluster), CmdLine: fmt.Sprintf("%s %s", ephemeralFlag, fooCluster),
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
{ {
Name: "get-target", Name: "get-target",
CmdLine: fmt.Sprintf("%s %s", targetFlag, fooCluster), CmdLine: fmt.Sprintf("%s %s", targetFlag, fooCluster),
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
// FIXME(howell): "airshipctl config get-cluster foo bar" will // FIXME(howell): "airshipctl config get-cluster foo bar" will
@ -84,12 +84,12 @@ func TestGetClusterCmd(t *testing.T) {
{ {
Name: "get-multiple-ephemeral", Name: "get-multiple-ephemeral",
CmdLine: fmt.Sprintf("%s %s %s", ephemeralFlag, fooCluster, barCluster), CmdLine: fmt.Sprintf("%s %s %s", ephemeralFlag, fooCluster, barCluster),
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
{ {
Name: "get-multiple-target", Name: "get-multiple-target",
CmdLine: fmt.Sprintf("%s %s %s", targetFlag, fooCluster, barCluster), CmdLine: fmt.Sprintf("%s %s %s", targetFlag, fooCluster, barCluster),
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
// FIXME(howell): "airshipctl config get-cluster // FIXME(howell): "airshipctl config get-cluster
@ -98,17 +98,17 @@ func TestGetClusterCmd(t *testing.T) {
{ {
Name: "get-all-ephemeral", Name: "get-all-ephemeral",
CmdLine: ephemeralFlag, CmdLine: ephemeralFlag,
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
{ {
Name: "get-all-target", Name: "get-all-target",
CmdLine: targetFlag, CmdLine: targetFlag,
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
}, },
{ {
Name: "missing", Name: "missing",
CmdLine: fmt.Sprintf("%s %s", targetFlag, missingCluster), CmdLine: fmt.Sprintf("%s %s", targetFlag, missingCluster),
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
Error: fmt.Errorf("cluster clustermissing information was not " + Error: fmt.Errorf("cluster clustermissing information was not " +
"found in the configuration"), "found in the configuration"),
}, },
@ -124,7 +124,7 @@ func TestNoClustersGetClusterCmd(t *testing.T) {
cmdTest := &testutil.CmdTest{ cmdTest := &testutil.CmdTest{
Name: "no-clusters", Name: "no-clusters",
CmdLine: "", CmdLine: "",
Cmd: cmd.NewCmdConfigGetCluster(settings), Cmd: cmd.NewGetClusterCommand(settings),
} }
testutil.RunTest(t, cmdTest) testutil.RunTest(t, cmdTest)
} }

View File

@ -25,30 +25,31 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
getContextLong = "Display a specific context, the current-context or all defined contexts if no name is provided" getContextLong = `
Display information about contexts such as associated manifests, users, and clusters.
`
getContextExample = fmt.Sprintf(`# List all the contexts airshipctl knows about getContextExample = `
# List all contexts
airshipctl config get-context airshipctl config get-context
# Display the current context # Display the current context
airshipctl config get-context --%v airshipctl config get-context --current
# Display a specific Context # Display a specific context
airshipctl config get-context e2e`, airshipctl config get-context exampleContext
config.FlagCurrentContext) `
) )
// A Context refers to a particular cluster, however it does not specify which of the cluster types // NewGetContextCommand creates a command for viewing cluster information
// it relates to. Getting explicit information about a particular context will depend // defined in the airshipctl config file.
// on the ClusterType flag. func NewGetContextCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
// NewCmdConfigGetContext returns a Command instance for 'config -Context' sub command
func NewCmdConfigGetContext(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.ContextOptions{} o := &config.ContextOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get-context NAME", Use: "get-context [NAME]",
Short: getContextLong, Short: "Get context information from the airshipctl config",
Long: getContextLong[1:],
Example: getContextExample, Example: getContextExample,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
airconfig := rootSettings.Config airconfig := rootSettings.Config
@ -88,7 +89,7 @@ func addGetContextFlags(o *config.ContextOptions, cmd *cobra.Command) {
flags.BoolVar( flags.BoolVar(
&o.CurrentContext, &o.CurrentContext,
config.FlagCurrentContext, "current",
false, false,
"retrieve the current context entry in airshipctl config") "get the current context")
} }

View File

@ -29,8 +29,6 @@ import (
) )
const ( const (
currentContextFlag = "--" + config.FlagCurrentContext
fooContext = "ContextFoo" fooContext = "ContextFoo"
barContext = "ContextBar" barContext = "ContextBar"
bazContext = "ContextBaz" bazContext = "ContextBaz"
@ -53,31 +51,31 @@ func TestGetContextCmd(t *testing.T) {
{ {
Name: "get-context", Name: "get-context",
CmdLine: fmt.Sprintf("%s", fooContext), CmdLine: fmt.Sprintf("%s", fooContext),
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
}, },
{ {
Name: "get-all-contexts", Name: "get-all-contexts",
CmdLine: fmt.Sprintf("%s %s", fooContext, barContext), CmdLine: fmt.Sprintf("%s %s", fooContext, barContext),
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
}, },
// This is not implemented yet // This is not implemented yet
{ {
Name: "get-multiple-contexts", Name: "get-multiple-contexts",
CmdLine: fmt.Sprintf("%s %s", fooContext, barContext), CmdLine: fmt.Sprintf("%s %s", fooContext, barContext),
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
}, },
{ {
Name: "missing", Name: "missing",
CmdLine: fmt.Sprintf("%s", missingContext), CmdLine: fmt.Sprintf("%s", missingContext),
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
Error: fmt.Errorf(`Context %s information was not Error: fmt.Errorf(`Context %s information was not
found in the configuration.`, missingContext), found in the configuration.`, missingContext),
}, },
{ {
Name: "get-current-context", Name: "get-current-context",
CmdLine: fmt.Sprintf("%s", currentContextFlag), CmdLine: "--current",
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
}, },
} }
@ -91,7 +89,7 @@ func TestNoContextsGetContextCmd(t *testing.T) {
cmdTest := &testutil.CmdTest{ cmdTest := &testutil.CmdTest{
Name: "no-contexts", Name: "no-contexts",
CmdLine: "", CmdLine: "",
Cmd: cmd.NewCmdConfigGetContext(settings), Cmd: cmd.NewGetContextCommand(settings),
} }
testutil.RunTest(t, cmdTest) testutil.RunTest(t, cmdTest)
} }

View File

@ -22,19 +22,31 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
configInitLong = "Generate initial configuration files for airshipctl" initLong = `
Generate an airshipctl config file and its associated kubeConfig file.
These files will be written to the $HOME/.airship directory, and will contain
default configurations.
NOTE: This will overwrite any existing config files in $HOME/.airship
`
) )
// NewCmdConfigInit returns a Command instance for 'config init' sub command // NewInitCommand creates a command for generating default airshipctl config files.
func NewCmdConfigInit(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewInitCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
configInitCmd := &cobra.Command{ // TODO(howell): It'd be nice to have a flag to tell
// airshipctl where to store the new files.
// TODO(howell): Currently, this command overwrites whatever the user
// has in their airship directory. We should remove that functionality
// as default and provide and optional --overwrite flag.
cmd := &cobra.Command{
Use: "init", Use: "init",
Short: configInitLong, Short: "Generate initial configuration files for airshipctl",
Long: initLong[1:],
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return rootSettings.Config.PersistConfig() return rootSettings.Config.PersistConfig()
}, },
} }
return configInitCmd return cmd
} }

View File

@ -27,7 +27,7 @@ func TestConfigInit(t *testing.T) {
{ {
Name: "config-init-help", Name: "config-init-help",
CmdLine: "-h", CmdLine: "-h",
Cmd: NewCmdConfigInit(nil), Cmd: NewInitCommand(nil),
}, },
} }

View File

@ -25,38 +25,43 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
setAuthInfoLong = fmt.Sprintf(`Sets a user entry in airshipctl config setAuthInfoLong = `
Specifying a name that already exists will merge new fields on top of existing values.`, Create or modify a user credential in the airshipctl config file.
)
setAuthInfoExample = fmt.Sprintf(` Note that specifying more than one authentication method is an error.
# Set only the "client-key" field on the "cluster-admin" `
# entry, without touching other values:
airshipctl config set-credentials cluster-admin --%v=~/.kube/admin.key
# Set basic auth for the "cluster-admin" entry setAuthInfoExample = `
airshipctl config set-credentials cluster-admin --%v=admin --%v=uXFGweU9l35qcif # Create a new user credential with basic auth
airshipctl config set-credentials exampleUser \
--username=exampleUser \
--password=examplePassword
# Embed client certificate data in the "cluster-admin" entry # Change the client-key of a user named admin
airshipctl config set-credentials cluster-admin --%v=~/.kube/admin.crt --%v=true`, airshipctl config set-credentials admin \
config.FlagUsername, --client-key=$HOME/.kube/admin.key
config.FlagUsername,
config.FlagPassword, # Change the username and password of the admin user
config.FlagCertFile, airshipctl config set-credentials admin \
config.FlagEmbedCerts, --username=admin \
) --password=uXFGweU9l35qcif
# Embed client certificate data of the admin user
airshipctl config set-credentials admin \
--client-certificate=$HOME/.kube/admin.crt \
--embed-certs
`
) )
// NewCmdConfigSetAuthInfo creates a command object for the "set-credentials" action, which // NewSetAuthInfoCommand creates a command for creating and modifying user
// defines a new AuthInfo airship config. // credentials in the airshipctl config file.
func NewCmdConfigSetAuthInfo(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewSetAuthInfoCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.AuthInfoOptions{} o := &config.AuthInfoOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "set-credentials NAME", Use: "set-credentials NAME",
Short: "Sets a user entry in the airshipctl config", Short: "Manage user credentials",
Long: setAuthInfoLong, Long: setAuthInfoLong[1:],
Example: setAuthInfoExample, Example: setAuthInfoExample,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@ -83,37 +88,37 @@ func addSetAuthInfoFlags(o *config.AuthInfoOptions, cmd *cobra.Command) {
flags.StringVar( flags.StringVar(
&o.ClientCertificate, &o.ClientCertificate,
config.FlagCertFile, "client-certificate",
"", "",
"Path to "+config.FlagCertFile+" file for the user entry in airshipctl") "path to a certificate")
flags.StringVar( flags.StringVar(
&o.ClientKey, &o.ClientKey,
config.FlagKeyFile, "client-key",
"", "",
"Path to "+config.FlagKeyFile+" file for the user entry in airshipctl") "path to a key file")
flags.StringVar( flags.StringVar(
&o.Token, &o.Token,
config.FlagBearerToken, "token",
"", "",
config.FlagBearerToken+" for the user entry in airshipctl. Mutually exclusive with username and password flags.") "token to use for the credential; mutually exclusive with username and password flags.")
flags.StringVar( flags.StringVar(
&o.Username, &o.Username,
config.FlagUsername, "username",
"", "",
config.FlagUsername+" for the user entry in airshipctl. Mutually exclusive with token flag.") "username for the credential; mutually exclusive with token flag.")
flags.StringVar( flags.StringVar(
&o.Password, &o.Password,
config.FlagPassword, "password",
"", "",
config.FlagPassword+" for the user entry in airshipctl. Mutually exclusive with token flag.") "password for the credential; mutually exclusive with token flag.")
flags.BoolVar( flags.BoolVar(
&o.EmbedCertData, &o.EmbedCertData,
config.FlagEmbedCerts, "embed-certs",
false, false,
"Embed client cert/key for the user entry in airshipctl") "if set, embed the client certificate/key into the credential")
} }

View File

@ -52,18 +52,18 @@ func TestConfigSetAuthInfo(t *testing.T) {
{ {
Name: "config-cmd-set-authinfo-with-help", Name: "config-cmd-set-authinfo-with-help",
CmdLine: "--help", CmdLine: "--help",
Cmd: cmd.NewCmdConfigSetAuthInfo(nil), Cmd: cmd.NewSetAuthInfoCommand(nil),
}, },
{ {
Name: "config-cmd-set-authinfo-too-many-args", Name: "config-cmd-set-authinfo-too-many-args",
CmdLine: "arg1 arg2", CmdLine: "arg1 arg2",
Cmd: cmd.NewCmdConfigSetAuthInfo(nil), Cmd: cmd.NewSetAuthInfoCommand(nil),
Error: fmt.Errorf("accepts %d arg(s), received %d", 1, 2), Error: fmt.Errorf("accepts %d arg(s), received %d", 1, 2),
}, },
{ {
Name: "config-cmd-set-authinfo-too-few-args", Name: "config-cmd-set-authinfo-too-few-args",
CmdLine: "", CmdLine: "",
Cmd: cmd.NewCmdConfigSetAuthInfo(nil), Cmd: cmd.NewSetAuthInfoCommand(nil),
Error: fmt.Errorf("accepts %d arg(s), received %d", 1, 0), Error: fmt.Errorf("accepts %d arg(s), received %d", 1, 0),
}, },
} }
@ -89,7 +89,7 @@ func initInputConfig(t *testing.T) (given *config.Config, cleanup func(*testing.
func (test setAuthInfoTest) run(t *testing.T) { func (test setAuthInfoTest) run(t *testing.T) {
settings := &environment.AirshipCTLSettings{Config: test.inputConfig} settings := &environment.AirshipCTLSettings{Config: test.inputConfig}
test.cmdTest.Cmd = cmd.NewCmdConfigSetAuthInfo(settings) test.cmdTest.Cmd = cmd.NewSetAuthInfoCommand(settings)
testutil.RunTest(t, test.cmdTest) testutil.RunTest(t, test.cmdTest)
afterRunConf := settings.Config afterRunConf := settings.Config
@ -122,8 +122,8 @@ func TestSetAuthInfo(t *testing.T) {
{ {
testName: "set-auth-info", testName: "set-auth-info",
flags: []string{ flags: []string{
"--" + config.FlagUsername + "=" + testUsername, "--username=" + testUsername,
"--" + config.FlagPassword + "=" + testPassword, "--password=" + testPassword,
}, },
userName: newUserName, userName: newUserName,
userPassword: testPassword, userPassword: testPassword,
@ -132,7 +132,7 @@ func TestSetAuthInfo(t *testing.T) {
{ {
testName: "modify-auth-info", testName: "modify-auth-info",
flags: []string{ flags: []string{
"--" + config.FlagPassword + "=" + testPassword + pwdDelta, "--password=" + testPassword + pwdDelta,
}, },
userName: existingUserName, userName: existingUserName,
userPassword: testPassword + pwdDelta, userPassword: testPassword + pwdDelta,

View File

@ -26,42 +26,47 @@ import (
"opendev.org/airship/airshipctl/pkg/log" "opendev.org/airship/airshipctl/pkg/log"
) )
var ( const (
setClusterLong = ` setClusterLong = `
Sets a cluster entry in arshipctl config. Create or modify a cluster in the airshipctl config files.
Specifying a name that already exists will merge new fields on top of existing values for those fields.`
setClusterExample = fmt.Sprintf(` Since a cluster can be either "ephemeral" or "target", you must specify
# Set only the server field on the e2e cluster entry without touching other values. cluster-type when managing clusters.
airshipctl config set-cluster e2e --%v=ephemeral --%v=https://1.2.3.4 `
# Embed certificate authority data for the e2e cluster entry setClusterExample = `
airshipctl config set-cluster e2e --%v=target --%v-authority=~/.airship/e2e/kubernetes.ca.crt # Set the server field on the ephemeral exampleCluster
airshipctl config set-cluster exampleCluster \
--cluster-type=ephemeral \
--server=https://1.2.3.4
# Disable cert checking for the dev cluster entry # Embed certificate authority data for the target exampleCluster
airshipctl config set-cluster e2e --%v=target --%v=true airshipctl config set-cluster exampleCluster \
--cluster-type=target \
--client-certificate-authority=$HOME/.airship/ca/kubernetes.ca.crt \
--embed-certs
# Configure Client Certificate # Disable certificate checking for the target exampleCluster
airshipctl config set-cluster e2e --%v=target --%v=true --%v=".airship/cert_file"`, airshipctl config set-cluster exampleCluster
config.FlagClusterType, --cluster-type=target \
config.FlagAPIServer, --insecure-skip-tls-verify
config.FlagClusterType,
config.FlagCAFile, # Configure client certificate for the target exampleCluster
config.FlagClusterType, airshipctl config set-cluster exampleCluster \
config.FlagInsecure, --cluster-type=target \
config.FlagClusterType, --embed-certs \
config.FlagEmbedCerts, --client-certificate=$HOME/.airship/cert_file
config.FlagCertFile) `
) )
// NewCmdConfigSetCluster creates a command object for the "set-cluster" action, which // NewSetClusterCommand creates a command for creating and modifying clusters
// defines a new cluster airshipctl config. // in the airshipctl config file.
func NewCmdConfigSetCluster(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewSetClusterCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.ClusterOptions{} o := &config.ClusterOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "set-cluster NAME", Use: "set-cluster NAME",
Short: "Sets a cluster entry in the airshipctl config", Short: "Manage clusters",
Long: setClusterLong, Long: setClusterLong[1:],
Example: setClusterExample, Example: setClusterExample,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@ -90,36 +95,36 @@ func addSetClusterFlags(o *config.ClusterOptions, cmd *cobra.Command) {
flags.StringVar( flags.StringVar(
&o.Server, &o.Server,
config.FlagAPIServer, "server",
"", "",
config.FlagAPIServer+" for the cluster entry in airshipctl config") "server to use for the cluster")
flags.StringVar( flags.StringVar(
&o.ClusterType, &o.ClusterType,
config.FlagClusterType, "cluster-type",
"", "",
config.FlagClusterType+" for the cluster entry in airshipctl config") "the type of the cluster to add or modify")
err := cmd.MarkFlagRequired(config.FlagClusterType) err := cmd.MarkFlagRequired("cluster-type")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
flags.BoolVar( flags.BoolVar(
&o.InsecureSkipTLSVerify, &o.InsecureSkipTLSVerify,
config.FlagInsecure, "insecure-skip-tls-verify",
true, true,
config.FlagInsecure+" for the cluster entry in airshipctl config") "if set, disable certificate checking")
flags.StringVar( flags.StringVar(
&o.CertificateAuthority, &o.CertificateAuthority,
config.FlagCAFile, "certificate-authority",
"", "",
"Path to "+config.FlagCAFile+" file for the cluster entry in airshipctl config") "path to a certificate authority")
flags.BoolVar( flags.BoolVar(
&o.EmbedCAData, &o.EmbedCAData,
config.FlagEmbedCerts, "embed-certs",
false, false,
config.FlagEmbedCerts+" for the cluster entry in airshipctl config") "if set, embed the client certificate/key into the cluster")
} }

View File

@ -73,10 +73,9 @@ func TestSetClusterWithCAFile(t *testing.T) {
givenConfig: given, givenConfig: given,
args: []string{tname}, args: []string{tname},
flags: []string{ flags: []string{
"--" + config.FlagClusterType + "=" + config.Ephemeral, "--cluster-type=ephemeral",
"--" + config.FlagEmbedCerts + "=false", "--certificate-authority=" + certFile,
"--" + config.FlagCAFile + "=" + certFile, "--insecure-skip-tls-verify=false",
"--" + config.FlagInsecure + "=false",
}, },
expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", testCluster, config.Ephemeral), expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", testCluster, config.Ephemeral),
expectedConfig: expected, expectedConfig: expected,
@ -113,10 +112,10 @@ func TestSetClusterWithCAFileData(t *testing.T) {
givenConfig: given, givenConfig: given,
args: []string{tname}, args: []string{tname},
flags: []string{ flags: []string{
"--" + config.FlagClusterType + "=" + config.Ephemeral, "--cluster-type=ephemeral",
"--" + config.FlagEmbedCerts + "=true", "--embed-certs",
"--" + config.FlagCAFile + "=" + certFile, "--certificate-authority=" + certFile,
"--" + config.FlagInsecure + "=false", "--insecure-skip-tls-verify=false",
}, },
expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", tname, config.Ephemeral), expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", tname, config.Ephemeral),
expectedConfig: expected, expectedConfig: expected,
@ -149,9 +148,8 @@ func TestSetCluster(t *testing.T) {
givenConfig: given, givenConfig: given,
args: []string{tname}, args: []string{tname},
flags: []string{ flags: []string{
"--" + config.FlagClusterType + "=" + config.Ephemeral, "--cluster-type=ephemeral",
"--" + config.FlagAPIServer + "=https://192.168.0.11", "--server=https://192.168.0.11",
"--" + config.FlagInsecure + "=false",
}, },
expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", tname, config.Ephemeral), expectedOutput: fmt.Sprintf("Cluster %q of type %q created.\n", tname, config.Ephemeral),
expectedConfig: expected, expectedConfig: expected,
@ -191,8 +189,8 @@ func TestModifyCluster(t *testing.T) {
givenConfig: given, givenConfig: given,
args: []string{tname}, args: []string{tname},
flags: []string{ flags: []string{
"--" + config.FlagClusterType + "=" + config.Ephemeral, "--cluster-type=ephemeral",
"--" + config.FlagAPIServer + "=https://192.168.0.99", "--server=https://192.168.0.99",
}, },
expectedOutput: fmt.Sprintf("Cluster %q of type %q modified.\n", tname, tctype), expectedOutput: fmt.Sprintf("Cluster %q of type %q modified.\n", tname, tctype),
expectedConfig: expected, expectedConfig: expected,
@ -204,7 +202,7 @@ func (test setClusterTest) run(t *testing.T) {
settings := &environment.AirshipCTLSettings{Config: test.givenConfig} settings := &environment.AirshipCTLSettings{Config: test.givenConfig}
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := cmd.NewCmdConfigSetCluster(settings) cmd := cmd.NewSetClusterCommand(settings)
cmd.SetOut(buf) cmd.SetOut(buf)
cmd.SetArgs(test.args) cmd.SetArgs(test.args)
err := cmd.Flags().Parse(test.flags) err := cmd.Flags().Parse(test.flags)
@ -218,7 +216,7 @@ func (test setClusterTest) run(t *testing.T) {
// Loads the Config File that was updated // Loads the Config File that was updated
afterRunConf := settings.Config afterRunConf := settings.Config
// Get ClusterType // Get ClusterType
tctypeFlag := cmd.Flag(config.FlagClusterType) tctypeFlag := cmd.Flag("cluster-type")
require.NotNil(t, tctypeFlag) require.NotNil(t, tctypeFlag)
tctype := tctypeFlag.Value.String() tctype := tctypeFlag.Value.String()

View File

@ -25,44 +25,40 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
setContextLong = ` setContextLong = `
Sets a context entry in arshipctl config. Create or modify a context in the airshipctl config files.
Specifying a name that already exists will merge new fields on top of existing values for those fields.` `
setContextExample = fmt.Sprintf(` setContextExample = `
# Create a completely new e2e context entry # Create a new context named "exampleContext"
airshipctl config set-context e2e --%v=kube-system --%v=manifest --%v=auth-info --%v=%v airshipctl config set-context exampleContext \
--namespace=kube-system \
--manifest=exampleManifest \
--user=exampleUser
--cluster-type=target
# Update the current-context to e2e # Update the manifest of the current-context
airshipctl config set-context e2e airshipctl config set-context \
--current \
# Update attributes of the current-context --manifest=exampleManifest
airshipctl config set-context --%s --%v=manifest`, `
config.FlagNamespace,
config.FlagManifest,
config.FlagAuthInfoName,
config.FlagClusterType,
config.Target,
config.FlagCurrent,
config.FlagManifest)
) )
// NewCmdConfigSetContext creates a command object for the "set-context" action, which // NewSetContextCommand creates a command for creating and modifying contexts
// creates and modifies contexts in the airshipctl config // in the airshipctl config
func NewCmdConfigSetContext(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewSetContextCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
o := &config.ContextOptions{} o := &config.ContextOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "set-context NAME", Use: "set-context NAME",
Short: "Switch to a new context or update context values in the airshipctl config", Short: "Manage contexts",
Long: setContextLong, Long: setContextLong[1:],
Example: setContextExample, Example: setContextExample,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
nFlags := cmd.Flags().NFlag() nFlags := cmd.Flags().NFlag()
if len(args) == 1 { if len(args) == 1 {
//context name is made optional with --current flag added // context name is made optional with --current flag added
o.Name = args[0] o.Name = args[0]
} }
if o.Name != "" && nFlags == 0 { if o.Name != "" && nFlags == 0 {
@ -93,37 +89,37 @@ func addSetContextFlags(o *config.ContextOptions, cmd *cobra.Command) {
flags.StringVar( flags.StringVar(
&o.Cluster, &o.Cluster,
config.FlagClusterName, "cluster",
"", "",
"sets the "+config.FlagClusterName+" for the specified context in the airshipctl config") "set the cluster for the specified context")
flags.StringVar( flags.StringVar(
&o.AuthInfo, &o.AuthInfo,
config.FlagAuthInfoName, "user",
"", "",
"sets the "+config.FlagAuthInfoName+" for the specified context in the airshipctl config") "set the user for the specified context")
flags.StringVar( flags.StringVar(
&o.Manifest, &o.Manifest,
config.FlagManifest, "manifest",
"", "",
"sets the "+config.FlagManifest+" for the specified context in the airshipctl config") "set the manifest for the specified context")
flags.StringVar( flags.StringVar(
&o.Namespace, &o.Namespace,
config.FlagNamespace, "namespace",
"", "",
"sets the "+config.FlagNamespace+" for the specified context in the airshipctl config") "set the namespace for the specified context")
flags.StringVar( flags.StringVar(
&o.ClusterType, &o.ClusterType,
config.FlagClusterType, "cluster-type",
"", "",
"sets the "+config.FlagClusterType+" for the specified context in the airshipctl config") "set the cluster-type for the specified context")
flags.BoolVar( flags.BoolVar(
&o.Current, &o.Current,
config.FlagCurrent, "current",
false, false,
"use current context from airshipctl config") "update the current context")
} }

View File

@ -49,17 +49,17 @@ func TestConfigSetContext(t *testing.T) {
{ {
Name: "config-cmd-set-context-with-help", Name: "config-cmd-set-context-with-help",
CmdLine: "--help", CmdLine: "--help",
Cmd: cmd.NewCmdConfigSetContext(nil), Cmd: cmd.NewSetContextCommand(nil),
}, },
{ {
Name: "config-cmd-set-context-no-flags", Name: "config-cmd-set-context-no-flags",
CmdLine: "context", CmdLine: "context",
Cmd: cmd.NewCmdConfigSetContext(nil), Cmd: cmd.NewSetContextCommand(nil),
}, },
{ {
Name: "config-cmd-set-context-too-many-args", Name: "config-cmd-set-context-too-many-args",
CmdLine: "arg1 arg2", CmdLine: "arg1 arg2",
Cmd: cmd.NewCmdConfigSetContext(nil), Cmd: cmd.NewSetContextCommand(nil),
Error: fmt.Errorf("accepts at most %d arg(s), received %d", 1, 2), Error: fmt.Errorf("accepts at most %d arg(s), received %d", 1, 2),
}, },
} }
@ -84,10 +84,10 @@ func TestSetContext(t *testing.T) {
testName: "set-context", testName: "set-context",
contextName: "dummycontext", contextName: "dummycontext",
flags: []string{ flags: []string{
"--" + config.FlagClusterType + "=" + config.Target, "--cluster-type=target",
"--" + config.FlagAuthInfoName + "=" + testUser, "--user=" + testUser,
"--" + config.FlagManifest + "=" + defaultManifest, "--manifest=" + defaultManifest,
"--" + config.FlagNamespace + "=" + defaultNamespace, "--namespace=" + defaultNamespace,
}, },
givenConfig: given, givenConfig: given,
manifest: defaultManifest, manifest: defaultManifest,
@ -102,7 +102,7 @@ func TestSetContext(t *testing.T) {
testName: "modify-context", testName: "modify-context",
contextName: "def_target", contextName: "def_target",
flags: []string{ flags: []string{
"--" + config.FlagManifest + "=" + testManifest, "--manifest=" + testManifest,
}, },
givenConfig: given, givenConfig: given,
manifest: testManifest, manifest: testManifest,
@ -129,7 +129,7 @@ func (test setContextTest) run(t *testing.T) {
// Get the Environment // Get the Environment
settings := &environment.AirshipCTLSettings{Config: test.givenConfig} settings := &environment.AirshipCTLSettings{Config: test.givenConfig}
test.cmdTest.Cmd = cmd.NewCmdConfigSetContext(settings) test.cmdTest.Cmd = cmd.NewSetContextCommand(settings)
testutil.RunTest(t, test.cmdTest) testutil.RunTest(t, test.cmdTest)
afterRunConf := settings.Config afterRunConf := settings.Config

View File

@ -1,19 +1,18 @@
Modify airshipctl config files using subcommands Manage the airshipctl config file
like "airshipctl config set-context my-context"
Usage: Usage:
config [command] config [command]
Available Commands: Available Commands:
get-cluster Display a specific cluster or all defined clusters if no name is provided get-cluster Get cluster information from the airshipctl config
get-context Display a specific context, the current-context or all defined contexts if no name is provided get-context Get context information from the airshipctl config
get-credentials Gets a user entry from the airshipctl config get-credentials Get user credentials from the airshipctl config
help Help about any command help Help about any command
init Generate initial configuration files for airshipctl init Generate initial configuration files for airshipctl
set-cluster Sets a cluster entry in the airshipctl config set-cluster Manage clusters
set-context Switch to a new context or update context values in the airshipctl config set-context Manage contexts
set-credentials Sets a user entry in the airshipctl config set-credentials Manage user credentials
use-context Switch to a different airshipctl context. use-context Switch to a different context
Flags: Flags:
-h, --help help for config -h, --help help for config

View File

@ -1,4 +1,8 @@
Generate initial configuration files for airshipctl Generate an airshipctl config file and its associated kubeConfig file.
These files will be written to the $HOME/.airship directory, and will contain
default configurations.
NOTE: This will overwrite any existing config files in $HOME/.airship
Usage: Usage:
init [flags] init [flags]

View File

@ -4,22 +4,32 @@ Usage:
Examples: Examples:
# Set only the "client-key" field on the "cluster-admin" # Create a new user credential with basic auth
# entry, without touching other values: airshipctl config set-credentials exampleUser \
airshipctl config set-credentials cluster-admin --username=~/.kube/admin.key --username=exampleUser \
--password=examplePassword
# Set basic auth for the "cluster-admin" entry # Change the client-key of a user named admin
airshipctl config set-credentials cluster-admin --username=admin --password=uXFGweU9l35qcif airshipctl config set-credentials admin \
--client-key=$HOME/.kube/admin.key
# Change the username and password of the admin user
airshipctl config set-credentials admin \
--username=admin \
--password=uXFGweU9l35qcif
# Embed client certificate data of the admin user
airshipctl config set-credentials admin \
--client-certificate=$HOME/.kube/admin.crt \
--embed-certs
# Embed client certificate data in the "cluster-admin" entry
airshipctl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true
Flags: Flags:
--client-certificate string Path to client-certificate file for the user entry in airshipctl --client-certificate string path to a certificate
--client-key string Path to client-key file for the user entry in airshipctl --client-key string path to a key file
--embed-certs Embed client cert/key for the user entry in airshipctl --embed-certs if set, embed the client certificate/key into the credential
-h, --help help for set-credentials -h, --help help for set-credentials
--password string password for the user entry in airshipctl. Mutually exclusive with token flag. --password string password for the credential; mutually exclusive with token flag.
--token string token for the user entry in airshipctl. Mutually exclusive with username and password flags. --token string token to use for the credential; mutually exclusive with username and password flags.
--username string username for the user entry in airshipctl. Mutually exclusive with token flag. --username string username for the credential; mutually exclusive with token flag.

View File

@ -4,22 +4,32 @@ Usage:
Examples: Examples:
# Set only the "client-key" field on the "cluster-admin" # Create a new user credential with basic auth
# entry, without touching other values: airshipctl config set-credentials exampleUser \
airshipctl config set-credentials cluster-admin --username=~/.kube/admin.key --username=exampleUser \
--password=examplePassword
# Set basic auth for the "cluster-admin" entry # Change the client-key of a user named admin
airshipctl config set-credentials cluster-admin --username=admin --password=uXFGweU9l35qcif airshipctl config set-credentials admin \
--client-key=$HOME/.kube/admin.key
# Change the username and password of the admin user
airshipctl config set-credentials admin \
--username=admin \
--password=uXFGweU9l35qcif
# Embed client certificate data of the admin user
airshipctl config set-credentials admin \
--client-certificate=$HOME/.kube/admin.crt \
--embed-certs
# Embed client certificate data in the "cluster-admin" entry
airshipctl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true
Flags: Flags:
--client-certificate string Path to client-certificate file for the user entry in airshipctl --client-certificate string path to a certificate
--client-key string Path to client-key file for the user entry in airshipctl --client-key string path to a key file
--embed-certs Embed client cert/key for the user entry in airshipctl --embed-certs if set, embed the client certificate/key into the credential
-h, --help help for set-credentials -h, --help help for set-credentials
--password string password for the user entry in airshipctl. Mutually exclusive with token flag. --password string password for the credential; mutually exclusive with token flag.
--token string token for the user entry in airshipctl. Mutually exclusive with username and password flags. --token string token to use for the credential; mutually exclusive with username and password flags.
--username string username for the user entry in airshipctl. Mutually exclusive with token flag. --username string username for the credential; mutually exclusive with token flag.

View File

@ -1,26 +1,37 @@
Sets a user entry in airshipctl config Create or modify a user credential in the airshipctl config file.
Specifying a name that already exists will merge new fields on top of existing values.
Note that specifying more than one authentication method is an error.
Usage: Usage:
set-credentials NAME [flags] set-credentials NAME [flags]
Examples: Examples:
# Set only the "client-key" field on the "cluster-admin" # Create a new user credential with basic auth
# entry, without touching other values: airshipctl config set-credentials exampleUser \
airshipctl config set-credentials cluster-admin --username=~/.kube/admin.key --username=exampleUser \
--password=examplePassword
# Set basic auth for the "cluster-admin" entry # Change the client-key of a user named admin
airshipctl config set-credentials cluster-admin --username=admin --password=uXFGweU9l35qcif airshipctl config set-credentials admin \
--client-key=$HOME/.kube/admin.key
# Change the username and password of the admin user
airshipctl config set-credentials admin \
--username=admin \
--password=uXFGweU9l35qcif
# Embed client certificate data of the admin user
airshipctl config set-credentials admin \
--client-certificate=$HOME/.kube/admin.crt \
--embed-certs
# Embed client certificate data in the "cluster-admin" entry
airshipctl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true
Flags: Flags:
--client-certificate string Path to client-certificate file for the user entry in airshipctl --client-certificate string path to a certificate
--client-key string Path to client-key file for the user entry in airshipctl --client-key string path to a key file
--embed-certs Embed client cert/key for the user entry in airshipctl --embed-certs if set, embed the client certificate/key into the credential
-h, --help help for set-credentials -h, --help help for set-credentials
--password string password for the user entry in airshipctl. Mutually exclusive with token flag. --password string password for the credential; mutually exclusive with token flag.
--token string token for the user entry in airshipctl. Mutually exclusive with username and password flags. --token string token to use for the credential; mutually exclusive with username and password flags.
--username string username for the user entry in airshipctl. Mutually exclusive with token flag. --username string username for the credential; mutually exclusive with token flag.

View File

@ -4,21 +4,25 @@ Usage:
Examples: Examples:
# Create a completely new e2e context entry # Create a new context named "exampleContext"
airshipctl config set-context e2e --namespace=kube-system --manifest=manifest --user=auth-info --cluster-type=target airshipctl config set-context exampleContext \
--namespace=kube-system \
--manifest=exampleManifest \
--user=exampleUser
--cluster-type=target
# Update the current-context to e2e # Update the manifest of the current-context
airshipctl config set-context e2e airshipctl config set-context \
--current \
--manifest=exampleManifest
# Update attributes of the current-context
airshipctl config set-context --current --manifest=manifest
Flags: Flags:
--cluster string sets the cluster for the specified context in the airshipctl config --cluster string set the cluster for the specified context
--cluster-type string sets the cluster-type for the specified context in the airshipctl config --cluster-type string set the cluster-type for the specified context
--current use current context from airshipctl config --current update the current context
-h, --help help for set-context -h, --help help for set-context
--manifest string sets the manifest for the specified context in the airshipctl config --manifest string set the manifest for the specified context
--namespace string sets the namespace for the specified context in the airshipctl config --namespace string set the namespace for the specified context
--user string sets the user for the specified context in the airshipctl config --user string set the user for the specified context

View File

@ -1,26 +1,28 @@
Create or modify a context in the airshipctl config files.
Sets a context entry in arshipctl config.
Specifying a name that already exists will merge new fields on top of existing values for those fields.
Usage: Usage:
set-context NAME [flags] set-context NAME [flags]
Examples: Examples:
# Create a completely new e2e context entry # Create a new context named "exampleContext"
airshipctl config set-context e2e --namespace=kube-system --manifest=manifest --user=auth-info --cluster-type=target airshipctl config set-context exampleContext \
--namespace=kube-system \
--manifest=exampleManifest \
--user=exampleUser
--cluster-type=target
# Update the current-context to e2e # Update the manifest of the current-context
airshipctl config set-context e2e airshipctl config set-context \
--current \
--manifest=exampleManifest
# Update attributes of the current-context
airshipctl config set-context --current --manifest=manifest
Flags: Flags:
--cluster string sets the cluster for the specified context in the airshipctl config --cluster string set the cluster for the specified context
--cluster-type string sets the cluster-type for the specified context in the airshipctl config --cluster-type string set the cluster-type for the specified context
--current use current context from airshipctl config --current update the current context
-h, --help help for set-context -h, --help help for set-context
--manifest string sets the manifest for the specified context in the airshipctl config --manifest string set the manifest for the specified context
--namespace string sets the namespace for the specified context in the airshipctl config --namespace string set the namespace for the specified context
--user string sets the user for the specified context in the airshipctl config --user string set the user for the specified context

View File

@ -4,8 +4,9 @@ Usage:
Examples: Examples:
# Switch to a context named "e2e" # Switch to a context named "exampleContext"
airshipctl config use-context e2e airshipctl config use-context exampleContext
Flags: Flags:
-h, --help help for use-context -h, --help help for use-context

View File

@ -4,8 +4,9 @@ Usage:
Examples: Examples:
# Switch to a context named "e2e" # Switch to a context named "exampleContext"
airshipctl config use-context e2e airshipctl config use-context exampleContext
Flags: Flags:
-h, --help help for use-context -h, --help help for use-context

View File

@ -1,7 +0,0 @@
LocationOfOrigin: ""
client-certificate: dummy_certificate
client-key: dummy_key
password: dummy_password
token: dummy_token
username: dummy_user

View File

@ -1,13 +1,15 @@
Error: Missing configuration: User credentials with name 'authinfoMissing' Error: Missing configuration: User credentials with name 'authinfoMissing'
Usage: Usage:
get-credentials NAME [flags] get-credentials [NAME] [flags]
Examples: Examples:
# List all the users airshipctl knows about
# List all user credentials
airshipctl config get-credentials airshipctl config get-credentials
# Display a specific user information # Display a specific user's credentials
airshipctl config get-credentials e2e airshipctl config get-credentials exampleUser
Flags: Flags:
-h, --help help for get-credentials -h, --help help for get-credentials

View File

@ -1,16 +1,17 @@
Error: Missing configuration: Cluster with name 'clusterMissing' of type 'target' Error: Missing configuration: Cluster with name 'clusterMissing' of type 'target'
Usage: Usage:
get-cluster NAME [flags] get-cluster [NAME] [flags]
Examples: Examples:
# List all the clusters airshipctl knows about # List all clusters
airshipctl config get-cluster airshipctl config get-cluster
# Display a specific cluster # Display a specific cluster
airshipctl config get-cluster e2e --cluster-type=ephemeral airshipctl config get-cluster --cluster-type=ephemeral exampleCluster
Flags: Flags:
--cluster-type string cluster-type for the cluster entry in airshipctl config --cluster-type string type of the desired cluster
-h, --help help for get-cluster -h, --help help for get-cluster

View File

@ -1,18 +1,20 @@
Error: Missing configuration: Context with name 'contextMissing' Error: Missing configuration: Context with name 'contextMissing'
Usage: Usage:
get-context NAME [flags] get-context [NAME] [flags]
Examples: Examples:
# List all the contexts airshipctl knows about
# List all contexts
airshipctl config get-context airshipctl config get-context
# Display the current context # Display the current context
airshipctl config get-context --current-context airshipctl config get-context --current
# Display a specific context
airshipctl config get-context exampleContext
# Display a specific Context
airshipctl config get-context e2e
Flags: Flags:
--current-context retrieve the current context entry in airshipctl config --current get the current context
-h, --help help for get-context -h, --help help for get-context

View File

@ -25,21 +25,23 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var ( const (
useContextLong = "Switch to a new context defined in the airshipctl config file." useContextLong = `
Switch to a different context defined in the airshipctl config file.
`
useContextExample = ` useContextExample = `
# Switch to a context named "e2e" # Switch to a context named "exampleContext"
airshipctl config use-context e2e` airshipctl config use-context exampleContext
`
) )
// NewCmdConfigUseContext creates a command object for the "use-context" action, which // NewUseContextCommand creates a command for switching to a defined airshipctl context.
// switches to a defined airshipctl context. func NewUseContextCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
func NewCmdConfigUseContext(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "use-context NAME", Use: "use-context NAME",
Short: "Switch to a different airshipctl context.", Short: "Switch to a different context",
Long: useContextLong, Long: useContextLong[1:],
Example: useContextExample, Example: useContextExample,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -31,18 +31,18 @@ func TestConfigUseContext(t *testing.T) {
{ {
Name: "config-use-context", Name: "config-use-context",
CmdLine: "dummy_context", CmdLine: "dummy_context",
Cmd: cmd.NewCmdConfigUseContext(settings), Cmd: cmd.NewUseContextCommand(settings),
}, },
{ {
Name: "config-use-context-no-args", Name: "config-use-context-no-args",
CmdLine: "", CmdLine: "",
Cmd: cmd.NewCmdConfigUseContext(settings), Cmd: cmd.NewUseContextCommand(settings),
Error: errors.New("accepts 1 arg(s), received 0"), Error: errors.New("accepts 1 arg(s), received 0"),
}, },
{ {
Name: "config-use-context-does-not-exist", Name: "config-use-context-does-not-exist",
CmdLine: "foo", CmdLine: "foo",
Cmd: cmd.NewCmdConfigUseContext(settings), Cmd: cmd.NewUseContextCommand(settings),
Error: errors.New("missing configuration: context with name 'foo'"), Error: errors.New("missing configuration: context with name 'foo'"),
}, },
} }

View File

@ -24,12 +24,12 @@ import (
func NewDocumentCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewDocumentCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
documentRootCmd := &cobra.Command{ documentRootCmd := &cobra.Command{
Use: "document", Use: "document",
Short: "manages deployment documents", Short: "Manage deployment documents",
} }
documentRootCmd.AddCommand(NewDocumentPullCommand(rootSettings)) documentRootCmd.AddCommand(NewPullCommand(rootSettings))
documentRootCmd.AddCommand(NewRenderCommand(rootSettings)) documentRootCmd.AddCommand(NewRenderCommand(rootSettings))
documentRootCmd.AddCommand(NewDocumentPluginCommand(rootSettings)) documentRootCmd.AddCommand(NewPluginCommand(rootSettings))
return documentRootCmd return documentRootCmd
} }

View File

@ -23,14 +23,22 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
var longDescription = `Subcommand reads configuration file CONFIG passed as const (
a first argument and determines a particular plugin to execute. Additional pluginLong = `
arguments may be passed to this sub-command abd can be used by the This command is meant to be used as a kustomize exec plugin.
particular plugin. CONFIG file must be structured as kubernetes
manifest (i.e. resource) and must have 'apiVersion' and 'kind' keys.
Example: The command reads the configuration file CONFIG passed as a first argument and
$ cat /tmp/generator.yaml determines a particular plugin to execute. Additional arguments may be passed
to this command and can be used by the particular plugin.
CONFIG must be a structured kubernetes manifest (i.e. resource) and must have
'apiVersion' and 'kind' keys. If the appropriate plugin was not found, the
command returns an error.
`
pluginExample = `
# Perform a replacement on a deployment. Prior to running this command,
# the file '/tmp/replacement.yaml' should be created as follows:
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
@ -45,21 +53,20 @@ replacements:
fieldrefs: fieldrefs:
- spec.template.spec.containers[name=nginx-latest].image - spec.template.spec.containers[name=nginx-latest].image
$ airshipctl document plugin /tmp/generator.yaml # The replacement can then be performed. Output defaults to stdout.
airshipctl document plugin /tmp/replacement.yaml
subcommand will try to identify appropriate plugin using apiVersion and
kind keys (a.k.a group, version, kind) as an identifier. If appropriate
plugin was not found command returns an error.
` `
)
// NewDocumentPluginCommand creates a new command which can act as kustomize // NewPluginCommand creates a new command which can act as kustomize
// exec plugin. // exec plugin.
func NewDocumentPluginCommand(rootSetting *environment.AirshipCTLSettings) *cobra.Command { func NewPluginCommand(rootSetting *environment.AirshipCTLSettings) *cobra.Command {
pluginCmd := &cobra.Command{ pluginCmd := &cobra.Command{
Use: "plugin CONFIG [ARGS]", Use: "plugin CONFIG [ARGS]",
Short: "used as kustomize exec plugin", Short: "Run as a kustomize exec plugin",
Long: longDescription, Long: pluginLong[1:],
Args: cobra.MinimumNArgs(1), Example: pluginExample,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := ioutil.ReadFile(args[0]) cfg, err := ioutil.ReadFile(args[0])
if err != nil { if err != nil {

View File

@ -26,19 +26,19 @@ func TestPlugin(t *testing.T) {
{ {
Name: "document-plugin-cmd-with-help", Name: "document-plugin-cmd-with-help",
CmdLine: "--help", CmdLine: "--help",
Cmd: NewDocumentPluginCommand(nil), Cmd: NewPluginCommand(nil),
}, },
{ {
Name: "document-plugin-cmd-with-empty-args", Name: "document-plugin-cmd-with-empty-args",
CmdLine: "", CmdLine: "",
Error: fmt.Errorf("requires at least 1 arg(s), only received 0"), Error: fmt.Errorf("requires at least 1 arg(s), only received 0"),
Cmd: NewDocumentPluginCommand(nil), Cmd: NewPluginCommand(nil),
}, },
{ {
Name: "document-plugin-cmd-with-nonexistent-config", Name: "document-plugin-cmd-with-nonexistent-config",
CmdLine: "/some/random/path.yaml", CmdLine: "/some/random/path.yaml",
Error: fmt.Errorf("open /some/random/path.yaml: no such file or directory"), Error: fmt.Errorf("open /some/random/path.yaml: no such file or directory"),
Cmd: NewDocumentPluginCommand(nil), Cmd: NewPluginCommand(nil),
}, },
} }

View File

@ -21,12 +21,12 @@ import (
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
) )
// NewDocumentPullCommand creates a new command for pulling airship document repositories // NewPullCommand creates a new command for pulling airship document repositories
func NewDocumentPullCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command { func NewPullCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
settings := pull.Settings{AirshipCTLSettings: rootSettings} settings := pull.Settings{AirshipCTLSettings: rootSettings}
documentPullCmd := &cobra.Command{ documentPullCmd := &cobra.Command{
Use: "pull", Use: "pull",
Short: "pulls documents from remote git repository", Short: "Pulls documents from remote git repository",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return settings.Pull() return settings.Pull()
}, },

View File

@ -50,12 +50,12 @@ func TestPull(t *testing.T) {
{ {
Name: "document-pull-cmd-with-defaults", Name: "document-pull-cmd-with-defaults",
CmdLine: "", CmdLine: "",
Cmd: NewDocumentPullCommand(getDummyAirshipSettings()), Cmd: NewPullCommand(getDummyAirshipSettings()),
}, },
{ {
Name: "document-pull-cmd-with-help", Name: "document-pull-cmd-with-help",
CmdLine: "--help", CmdLine: "--help",
Cmd: NewDocumentPullCommand(nil), Cmd: NewPullCommand(nil),
}, },
} }

View File

@ -46,33 +46,33 @@ func addRenderFlags(settings *render.Settings, cmd *cobra.Command) {
"label", "label",
"l", "l",
nil, nil,
"Filter documents by Labels") "filter documents by Labels")
flags.StringArrayVarP( flags.StringArrayVarP(
&settings.Annotation, &settings.Annotation,
"annotation", "annotation",
"a", "a",
nil, nil,
"Filter documents by Annotations") "filter documents by Annotations")
flags.StringArrayVarP( flags.StringArrayVarP(
&settings.GroupVersion, &settings.GroupVersion,
"apiversion", "apiversion",
"g", "g",
nil, nil,
"Filter documents by API version") "filter documents by API version")
flags.StringArrayVarP( flags.StringArrayVarP(
&settings.Kind, &settings.Kind,
"kind", "kind",
"k", "k",
nil, nil,
"Filter documents by Kinds") "filter documents by Kinds")
flags.StringVarP( flags.StringVarP(
&settings.RawFilter, &settings.RawFilter,
"filter", "filter",
"f", "f",
"", "",
"Logical expression for document filtering") "logical expression for document filtering")
} }

View File

@ -4,9 +4,9 @@ Usage:
render [flags] render [flags]
Flags: Flags:
-a, --annotation stringArray Filter documents by Annotations -a, --annotation stringArray filter documents by Annotations
-g, --apiversion stringArray Filter documents by API version -g, --apiversion stringArray filter documents by API version
-f, --filter string Logical expression for document filtering -f, --filter string logical expression for document filtering
-h, --help help for render -h, --help help for render
-k, --kind stringArray Filter documents by Kinds -k, --kind stringArray filter documents by Kinds
-l, --label stringArray Filter documents by Labels -l, --label stringArray filter documents by Labels

View File

@ -2,6 +2,28 @@ Error: requires at least 1 arg(s), only received 0
Usage: Usage:
plugin CONFIG [ARGS] [flags] plugin CONFIG [ARGS] [flags]
Examples:
# Perform a replacement on a deployment. Prior to running this command,
# the file '/tmp/replacement.yaml' should be created as follows:
---
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: notImportantHere
replacements:
- source:
value: nginx:newtag
target:
objref:
kind: Deployment
fieldrefs:
- spec.template.spec.containers[name=nginx-latest].image
# The replacement can then be performed. Output defaults to stdout.
airshipctl document plugin /tmp/replacement.yaml
Flags: Flags:
-h, --help help for plugin -h, --help help for plugin

View File

@ -1,11 +1,20 @@
Subcommand reads configuration file CONFIG passed as This command is meant to be used as a kustomize exec plugin.
a first argument and determines a particular plugin to execute. Additional
arguments may be passed to this sub-command abd can be used by the
particular plugin. CONFIG file must be structured as kubernetes
manifest (i.e. resource) and must have 'apiVersion' and 'kind' keys.
Example: The command reads the configuration file CONFIG passed as a first argument and
$ cat /tmp/generator.yaml determines a particular plugin to execute. Additional arguments may be passed
to this command and can be used by the particular plugin.
CONFIG must be a structured kubernetes manifest (i.e. resource) and must have
'apiVersion' and 'kind' keys. If the appropriate plugin was not found, the
command returns an error.
Usage:
plugin CONFIG [ARGS] [flags]
Examples:
# Perform a replacement on a deployment. Prior to running this command,
# the file '/tmp/replacement.yaml' should be created as follows:
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
@ -20,14 +29,9 @@ replacements:
fieldrefs: fieldrefs:
- spec.template.spec.containers[name=nginx-latest].image - spec.template.spec.containers[name=nginx-latest].image
$ airshipctl document plugin /tmp/generator.yaml # The replacement can then be performed. Output defaults to stdout.
airshipctl document plugin /tmp/replacement.yaml
subcommand will try to identify appropriate plugin using apiVersion and
kind keys (a.k.a group, version, kind) as an identifier. If appropriate
plugin was not found command returns an error.
Usage:
plugin CONFIG [ARGS] [flags]
Flags: Flags:
-h, --help help for plugin -h, --help help for plugin

View File

@ -2,6 +2,28 @@ Error: open /some/random/path.yaml: no such file or directory
Usage: Usage:
plugin CONFIG [ARGS] [flags] plugin CONFIG [ARGS] [flags]
Examples:
# Perform a replacement on a deployment. Prior to running this command,
# the file '/tmp/replacement.yaml' should be created as follows:
---
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: notImportantHere
replacements:
- source:
value: nginx:newtag
target:
objref:
kind: Deployment
fieldrefs:
- spec.template.spec.containers[name=nginx-latest].image
# The replacement can then be performed. Output defaults to stdout.
airshipctl document plugin /tmp/replacement.yaml
Flags: Flags:
-h, --help help for plugin -h, --help help for plugin

View File

@ -1,4 +1,4 @@
pulls documents from remote git repository Pulls documents from remote git repository
Usage: Usage:
pull [flags] pull [flags]

View File

@ -35,17 +35,17 @@ import (
// NewAirshipCTLCommand creates a root `airshipctl` command with the default commands attached // NewAirshipCTLCommand creates a root `airshipctl` command with the default commands attached
func NewAirshipCTLCommand(out io.Writer) (*cobra.Command, *environment.AirshipCTLSettings, error) { func NewAirshipCTLCommand(out io.Writer) (*cobra.Command, *environment.AirshipCTLSettings, error) {
rootCmd, settings, err := NewRootCmd(out) rootCmd, settings, err := NewRootCommand(out)
return AddDefaultAirshipCTLCommands(rootCmd, settings), settings, err return AddDefaultAirshipCTLCommands(rootCmd, settings), settings, err
} }
// NewRootCmd creates the root `airshipctl` command. All other commands are // NewRootCommand creates the root `airshipctl` command. All other commands are
// subcommands branching from this one // subcommands branching from this one
func NewRootCmd(out io.Writer) (*cobra.Command, *environment.AirshipCTLSettings, error) { func NewRootCommand(out io.Writer) (*cobra.Command, *environment.AirshipCTLSettings, error) {
settings := &environment.AirshipCTLSettings{} settings := &environment.AirshipCTLSettings{}
rootCmd := &cobra.Command{ rootCmd := &cobra.Command{
Use: "airshipctl", Use: "airshipctl",
Short: "airshipctl is a unified entrypoint to various airship components", Short: "A unified entrypoint to various airship components",
SilenceErrors: true, SilenceErrors: true,
SilenceUsage: true, SilenceUsage: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {

View File

@ -31,19 +31,19 @@ import (
func TestRoot(t *testing.T) { func TestRoot(t *testing.T) {
tests := []*testutil.CmdTest{ tests := []*testutil.CmdTest{
{ {
Name: "rootCmd-with-no-defaults", Name: "rootCmd-with-no-subcommands",
CmdLine: "-h", CmdLine: "--help",
Cmd: getVanillaRootCmd(t), Cmd: getVanillaRootCommand(t),
}, },
{ {
Name: "rootCmd-with-defaults", Name: "rootCmd-with-default-subcommands",
CmdLine: "-h", CmdLine: "--help",
Cmd: getDefaultRootCmd(t), Cmd: getDefaultRootCommand(t),
}, },
{ {
Name: "specialized-rootCmd-with-bootstrap", Name: "specialized-rootCmd-with-bootstrap",
CmdLine: "-h", CmdLine: "--help",
Cmd: getSpecializedRootCmd(t), Cmd: getSpecializedRootCommand(t),
}, },
} }
@ -78,7 +78,7 @@ func TestFlagLoading(t *testing.T) {
t.Run(tt.name, func(subTest *testing.T) { t.Run(tt.name, func(subTest *testing.T) {
// We don't care about the output of this test, so toss // We don't care about the output of this test, so toss
// it into a throwaway &bytes.buffer{} // it into a throwaway &bytes.buffer{}
rootCmd, settings, err := cmd.NewRootCmd(&bytes.Buffer{}) rootCmd, settings, err := cmd.NewRootCommand(&bytes.Buffer{})
require.NoError(t, err) require.NoError(t, err)
rootCmd.SetArgs(tt.args) rootCmd.SetArgs(tt.args)
@ -90,22 +90,22 @@ func TestFlagLoading(t *testing.T) {
} }
} }
func getVanillaRootCmd(t *testing.T) *cobra.Command { func getVanillaRootCommand(t *testing.T) *cobra.Command {
t.Helper() t.Helper()
rootCmd, _, err := cmd.NewRootCmd(nil) rootCmd, _, err := cmd.NewRootCommand(nil)
require.NoError(t, err, "Could not create root commands") require.NoError(t, err, "Could not create root commands")
return rootCmd return rootCmd
} }
func getDefaultRootCmd(t *testing.T) *cobra.Command { func getDefaultRootCommand(t *testing.T) *cobra.Command {
t.Helper() t.Helper()
rootCmd, _, err := cmd.NewAirshipCTLCommand(nil) rootCmd, _, err := cmd.NewAirshipCTLCommand(nil)
require.NoError(t, err, "Could not create root commands") require.NoError(t, err, "Could not create root commands")
return rootCmd return rootCmd
} }
func getSpecializedRootCmd(t *testing.T) *cobra.Command { func getSpecializedRootCommand(t *testing.T) *cobra.Command {
rootCmd := getVanillaRootCmd(t) rootCmd := getVanillaRootCommand(t)
rootCmd.AddCommand(bootstrap.NewBootstrapCommand(&environment.AirshipCTLSettings{})) rootCmd.AddCommand(bootstrap.NewBootstrapCommand(&environment.AirshipCTLSettings{}))
return rootCmd return rootCmd
} }

View File

@ -21,7 +21,7 @@ func NewGenerateCommand() *cobra.Command {
generateRootCmd := &cobra.Command{ generateRootCmd := &cobra.Command{
Use: "generate", Use: "generate",
// TODO(howell): Make this more expressive // TODO(howell): Make this more expressive
Short: "generates various secrets", Short: "Generate various secrets",
} }
generateRootCmd.AddCommand(NewGenerateMasterPassphraseCommand()) generateRootCmd.AddCommand(NewGenerateMasterPassphraseCommand())

View File

@ -27,7 +27,7 @@ func NewGenerateMasterPassphraseCommand() *cobra.Command {
masterPassphraseCmd := &cobra.Command{ masterPassphraseCmd := &cobra.Command{
Use: "masterpassphrase", Use: "masterpassphrase",
// TODO(howell): Make this more expressive // TODO(howell): Make this more expressive
Short: "generates a secure master passphrase", Short: "Generates a secure master passphrase",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
engine := secret.NewPassphraseEngine(nil) engine := secret.NewPassphraseEngine(nil)
masterPassphrase := engine.GeneratePassphrase() masterPassphrase := engine.GeneratePassphrase()

View File

@ -25,7 +25,7 @@ func NewSecretCommand() *cobra.Command {
secretRootCmd := &cobra.Command{ secretRootCmd := &cobra.Command{
Use: "secret", Use: "secret",
// TODO(howell): Make this more expressive // TODO(howell): Make this more expressive
Short: "manages secrets", Short: "Manage secrets",
} }
secretRootCmd.AddCommand(generate.NewGenerateCommand()) secretRootCmd.AddCommand(generate.NewGenerateCommand())

View File

@ -1,17 +1,17 @@
airshipctl is a unified entrypoint to various airship components A unified entrypoint to various airship components
Usage: Usage:
airshipctl [command] airshipctl [command]
Available Commands: Available Commands:
bootstrap Bootstrap ephemeral Kubernetes cluster bootstrap Bootstrap ephemeral Kubernetes cluster
cluster Control Kubernetes cluster cluster Manage Kubernetes clusters
completion Generate autocompletions script for the specified shell (bash or zsh) completion Generate completion script for the specified shell (bash or zsh)
config Modify airshipctl config files config Manage the airshipctl config file
document manages deployment documents document Manage deployment documents
help Help about any command help Help about any command
remote Control remote entities, i.e. hosts. remote Control remote entities, i.e. hosts.
secret manages secrets secret Manage secrets
version Show the version number of airshipctl version Show the version number of airshipctl
Flags: Flags:

View File

@ -1,4 +1,4 @@
airshipctl is a unified entrypoint to various airship components A unified entrypoint to various airship components
Usage: Usage:
airshipctl [command] airshipctl [command]

View File

@ -1,4 +1,4 @@
airshipctl is a unified entrypoint to various airship components A unified entrypoint to various airship components
Usage: Usage:
airshipctl [command] airshipctl [command]

View File

@ -22,7 +22,7 @@ import (
"opendev.org/airship/airshipctl/pkg/util" "opendev.org/airship/airshipctl/pkg/util"
) )
// NewVersionCommand prints out the versions of airshipctl and its underlying tools // NewVersionCommand creates a command for displaying the version of airshipctl.
func NewVersionCommand() *cobra.Command { func NewVersionCommand() *cobra.Command {
versionCmd := &cobra.Command{ versionCmd := &cobra.Command{
Use: "version", Use: "version",

View File

@ -19,8 +19,9 @@
AirshipCTL CLI AirshipCTL CLI
============== ==============
The AirshipCTL CLI is used in conjunction with the binary created by running ``make build``. This binary, by default, The AirshipCTL CLI is used in conjunction with the binary created by running
is created in the ``airshipctl/bin/`` directory. ``make build``. This binary, by default, is created in the ``airshipctl/bin/``
directory.
CLI Options CLI Options
@ -30,15 +31,15 @@ CLI Options
Prints help for a specific command or command group. Prints help for a specific command or command group.
**\\-\\-debug** (Optional, default: false) **\\-\\-debug** (default: false)
Enables verbose output of commands. Enables verbose output of commands.
**\\-\\-airshipconf** (Optional, default: `$HOME/.airship/config`) **\\-\\-airshipconf** (default: `$HOME/.airship/config`)
Path to file for airshipctl configuration. Path to file for airshipctl configuration.
**\\-\\-kubeconfig** (Optional, default: `$HOME/.airship/kubeconfig`) **\\-\\-kubeconfig** (default: `$HOME/.airship/kubeconfig`)
Path to kubeconfig associated with airshipctl configuration. Path to kubeconfig associated with airshipctl configuration.
@ -67,11 +68,11 @@ Usage:
Completion Completion
---------- ----------
Generate autocompletion script for airshipctl for the specified shell (bash or zsh). Generate completion script for airshipctl for the specified shell (bash or zsh).
**shell** (Required) **shell** (Required)
Shell to generate autocompletion script for. Supported values are `bash` and `zsh` Shell to generate completion script for. Supported values are `bash` and `zsh`
Usage: Usage:
@ -82,13 +83,13 @@ Usage:
Examples Examples
^^^^^^^^ ^^^^^^^^
This command can generate bash autocompletion. e.g. Save shell completion to a file
:: ::
$ airshipctl completion bash $ airshipctl completion bash > $HOME/.airship_completions
Which can be sourced as such: Apply completions to the current shell
:: ::
@ -128,22 +129,23 @@ Usage:
Cluster Group Cluster Group
============= =============
Control Kubernetes cluster. This command provides capabilities for interacting with a Kubernetes cluster,
such as getting status and deploying initial infrastructure.
InitInfra InitInfra
------------ ------------
Deploy initinfra components to cluster. Deploy initinfra components to cluster.
**cluster-type** (Optional, default:"ephemeral") **cluster-type** (default:"ephemeral")
Select cluster type to deploy initial infrastructure to, currently only ephemeral is supported. Select cluster type to deploy initial infrastructure to, currently only ephemeral is supported.
**\\-\\-dry-run** (Optional). **\\-\\-dry-run**
Don't deliver documents to the cluster, simulate the changes instead. Don't deliver documents to the cluster, simulate the changes instead.
**\\-\\-prune** (Optional, default:false) **\\-\\-prune** (default: false)
If set to true, command will delete all kubernetes resources that are not defined in airship documents and have If set to true, command will delete all kubernetes resources that are not defined in airship documents and have
airshipit.org/deployed=initinfra label airshipit.org/deployed=initinfra label
@ -159,20 +161,20 @@ Usage:
Config Group Config Group
============ ============
Modify airshipctl config files Manage the airshipctl config file
Get-Cluster Get-Cluster
----------- -----------
Display cluster information. Get cluster information from the airshipctl config.
**name** (Optional, default: all defined clusters) **name** (Optional, default: all defined clusters)
Displays a specific cluster if specified, or if left blank all defined clusters. Display a specific cluster or all defined clusters if no name is provided.
**\\-\\-cluster-type** (Required). **\\-\\-cluster-type** (Required if **name** is provided).
cluster-type for the cluster-entry in airshipctl config. Currently only ephemeral cluster types are supported. The type of the desired cluster. Valid values are from [ephemeral|target].
Usage: Usage:
@ -183,7 +185,7 @@ Usage:
Examples Examples
^^^^^^^^ ^^^^^^^^
List all the clusters airshipctl knows about: List all the clusters:
:: ::
@ -198,13 +200,13 @@ Display a specific cluster:
Get-Context Get-Context
----------- -----------
Displays context information Display information about contexts such as associated manifests, users, and clusters.
**name** (Optional, default: all defined contexts) **name** (Optional, default: all defined contexts)
Displays a named context, if no name is provided display all defined contexts. Displays a named context, if no name is provided display all defined contexts.
**\\-\\-current-context** (Optional, default:false) **\\-\\-current-context** (default: false)
Display the current context, supersedes the `name` argument. Display the current context, supersedes the `name` argument.
@ -233,43 +235,47 @@ For a named context:
:: ::
airshipctl config get-context e2e airshipctl config get-context exampleContext
Get-Credentials Get-Credentials
--------------- ---------------
Display a user's information. Get user credentials from the airshipctl config.
**name** (Optional, default: all defined users) **name** (Optional, default: all defined users)
Display a specific user's information. If no name is specified, list all defined users. Display a specific user's credentials, or all defined user credentials if no name is provided.
Usage: Usage:
:: ::
airshipctl config get-credentials <NAME> airshipctl config get-credentials <name>
Examples Examples
^^^^^^^^ ^^^^^^^^
List all the users airshipctl knows about: List all user credentials:
:: ::
airshipctl config get-credentials airshipctl config get-credentials
Display a specific user's information: Display a specific user's credentials:
:: ::
airshipctl config get-credentials e2e airshipctl config get-credentials exampleUser
Init Init
---- ----
Generate initial configuration files for airshipctl Generate an airshipctl config file and its associated kubeConfig file.
These files will be written to the $HOME/.airship directory, and will contain
default configurations.
.. note:: This will overwrite any existing config files in $HOME/.airship
Usage: Usage:
@ -280,35 +286,34 @@ Usage:
Set-Cluster Set-Cluster
----------- -----------
Sets a cluster entry in the airshipctl config. Create or modify a cluster in the airshipctl config files.
Since a cluster can be either "ephemeral" or "target", you must specify
cluster-type when managing clusters.
**name** (Required) **name** (Required)
The name of the cluster to add to airshipctl config. The name of the cluster to add or modify in the airshipctl config file.
.. note:: **\\-\\-certificate-authority**
Specifying a name that already exists will merge new fields on top of existing values for those fields. Path to a certificate authority file
**\\-\\-certificate-authority** (Optional)
Path to certificate-authority file for the cluster entry in airshipctl config
**\\-\\-certificate-authority** (Required) **\\-\\-certificate-authority** (Required)
Cluster-type for the cluster entry in airshipctl config The type of the cluster to add or modify
**\\-\\-embed-certs** (Optional) **\\-\\-embed-certs** (default: false)
Embed-certs for the cluster entry in airshipctl config If set, embed the client certificate/key into the cluster
**\\-\\-insecure-skip-tls-verify** (Optional, default:true) **\\-\\-insecure-skip-tls-verify** (default: true)
Insecure-skip-tls-verify for the cluster entry in airshipctl config If set, disable certificate checking
**\\-\\-server** (Optional) **\\-\\-server**
Server for the cluster entry in airshipctl config Server to use for the cluster
Usage: Usage:
@ -319,62 +324,72 @@ Usage:
Examples Examples
^^^^^^^^ ^^^^^^^^
Set only the server field on the e2e cluster entry without touching other values: Set the server field on the ephemeral exampleCluster:
:: ::
airshipctl config set-cluster e2e --cluster-type=ephemeral --server=https://1.2.3.4 airshipctl config set-cluster exampleCluster \
--cluster-type=ephemeral \
--server=https://1.2.3.4
Embed certificate authority data for the e2e cluster entry: Embed certificate authority data for the target exampleCluster:
:: ::
airshipctl config set-cluster e2e --cluster-type=target --certificate-authority-authority=~/.airship/e2e/kubernetes.ca.crt airshipctl config set-cluster exampleCluster \
--cluster-type=target \
--client-certificate-authority=$HOME/.airship/ca/kubernetes.ca.crt \
--embed-certs
Disable cert checking for the dev cluster entry: Disable certificate checking for the target exampleCluster:
:: ::
airshipctl config set-cluster e2e --cluster-type=target --insecure-skip-tls-verify=true airshipctl config set-cluster exampleCluster
--cluster-type=target \
--insecure-skip-tls-verify
Configure client certificate: Configure client certificate for the target exampleCluster:
:: ::
airshipctl config set-cluster e2e --cluster-type=target --embed-certs=true --client-certificate=".airship/cert_file" airshipctl config set-cluster exampleCluster \
--cluster-type=target \
--embed-certs \
--client-certificate=$HOME/.airship/cert_file
Set-Context Set-Context
----------- -----------
Switch to a new context, or update context values in the airshipctl config Create or modify a context in the airshipctl config files.
**name** (Required) **name** (Required)
The name of the context to set. The name of the context to add or modify in the airshipctl config file.
**\\-\\-cluster-string** **\\-\\-cluster**
Sets the cluster for the specified context in the airshipctl config. Set the cluster for the specified context.
**\\-\\-cluster-type** **\\-\\-cluster-type**
Sets the cluster-type for the specified context in the airshipctl config. Set the cluster-type for the specified context.
**\\-\\-current** **\\-\\-current**
Use current context from airshipctl config. Update the current context.
**\\-\\-manifest** **\\-\\-manifest**
Sets the manifest for the specified context in the airshipctl config. Set the manifest for the specified context.
**\\-\\-namespace** **\\-\\-namespace**
Sets the namespace for the specified context in the airshipctl config. Set the namespace for the specified context.
**\\-\\-user** **\\-\\-user**
Sets the user for the specified context in the airshipctl config. Set the user for the specified context.
Usage: Usage:
@ -385,63 +400,63 @@ Usage:
Examples Examples
^^^^^^^^ ^^^^^^^^
Create a completely new e2e context entry: Create a new context named "exampleContext":
:: ::
airshipctl config set-context e2e --namespace=kube-system --manifest=manifest --user=auth-info --cluster-type=target airshipctl config set-context exampleContext \
--namespace=kube-system \
--manifest=exampleManifest \
--user=exampleUser
--cluster-type=target
Update the current-context to e2e: Update the manifest of the current-context:
:: ::
airshipctl config set-context e2e airshipctl config set-context \
--current \
Update attributes of the current-context: --manifest=exampleManifest
::
airshipctl config set-context --current --manifest=manifest
Set-Credentials Set-Credentials
--------------- ---------------
Sets a user entry in the airshipctl config. Create or modify a user credential in the airshipctl config file.
.. note:: Specifying more than one authentication method is an error.
**name** (Required) **name** (Required)
The user entry to update in airshipctl config. The user entry to update in airshipctl config.
.. note:: Specifying a name that already exists will merge new fields on top of existing values.
**\\-\\-client-certificate** **\\-\\-client-certificate**
Path to client-certificate file for the user entry in airshipctl Path to a certificate file.
**\\-\\-client-key** **\\-\\-client-key**
Path to client-key file for the user entry in airshipctl Path to a key file.
**\\-\\-embed-certs** **\\-\\-embed-certs**
Embed client cert/key for the user entry in airshipctl If set, embed the client certificate/key into the credential.
**\\-\\-password** **\\-\\-password**
Password for the user entry in airshipctl Password for the credential
.. note:: Username and Password flags are mutually exclusive with Token flag .. note:: Username and Password flags are mutually exclusive with Token flag
**\\-\\-token** **\\-\\-token**
Token for the user entry in airshipctl Token to use for the credential
.. note:: Username and Password flags are mutually exclusive with Token flag .. note:: Username and Password flags are mutually exclusive with Token flag
**\\-\\-username** **\\-\\-username**
Username for the user entry in airshipctl Username for the credential
.. note:: Username and Password flags are mutually exclusive with Token flag .. note:: Username and Password flags are mutually exclusive with Token flag
@ -454,23 +469,36 @@ Usage:
Examples Examples
^^^^^^^^ ^^^^^^^^
Set only the "client-key" field on the "cluster-admin" entry, without touching other values: Create a new user credential with basic auth:
:: ::
airshipctl config set-credentials cluster-admin --username=~/.kube/admin.key airshipctl config set-credentials exampleUser \
--username=exampleUser \
--password=examplePassword
Set basic auth for the "cluster-admin" entry Change the client-key of a user named admin
:: ::
airshipctl config set-credentials cluster-admin --username=admin --password=uXFGweU9l35qcif airshipctl config set-credentials admin \
--client-key=$HOME/.kube/admin.key
Embed client certificate data in the "cluster-admin" entry Change the username and password of the admin user
:: ::
airshipctl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true airshipctl config set-credentials admin \
--username=admin \
--password=uXFGweU9l35qcif
Embed client certificate data of the admin user
::
airshipctl config set-credentials admin \
--client-certificate=$HOME/.kube/admin.crt \
--embed-certs
.. _document-group: .. _document-group:

View File

@ -54,26 +54,3 @@ const (
AirshipDefaultIsoURL = "http://localhost:8099/debian-custom.iso" AirshipDefaultIsoURL = "http://localhost:8099/debian-custom.iso"
AirshipDefaultRemoteType = redfish.ClientType AirshipDefaultRemoteType = redfish.ClientType
) )
const (
FlagAPIServer = "server"
FlagAuthInfoName = "user"
FlagBearerToken = "token"
FlagCAFile = "certificate-authority"
FlagCertFile = "client-certificate"
FlagClusterName = "cluster"
FlagClusterType = "cluster-type"
FlagCurrentContext = "current-context"
FlagConfigFilePath = "airshipconf"
FlagEmbedCerts = "embed-certs"
FlagInsecure = "insecure-skip-tls-verify"
FlagKeyFile = "client-key"
FlagManifest = "manifest"
FlagNamespace = "namespace"
FlagPassword = "password"
FlagUsername = "username"
FlagCurrent = "current"
)

View File

@ -54,21 +54,33 @@ type ClusterOptions struct {
EmbedCAData bool EmbedCAData bool
} }
// TODO(howell): The following functions are tightly coupled with flags passed
// on the command line. We should find a way to remove this coupling, since it
// is possible to create (and validate) these objects without using the command
// line.
// TODO(howell): strongly type the errors in this file
func (o *AuthInfoOptions) Validate() error { func (o *AuthInfoOptions) Validate() error {
// TODO(howell): This prevents a user of airshipctl from creating a
// credential with both a bearer-token and a user/password, but it does
// not prevent a user from adding a bearer-token to a credential which
// already had a user/pass and visa-versa. This could create bugs if a
// user at first chooses one method, but later switches to another.
if o.Token != "" && (o.Username != "" || o.Password != "") { if o.Token != "" && (o.Username != "" || o.Password != "") {
return fmt.Errorf("you cannot specify more than one authentication method at the same time: --%v or --%v/--%v", // TODO(howell): strongly type this error
FlagBearerToken, FlagUsername, FlagPassword) return errors.New("you must specify either token or a username/password")
} }
if !o.EmbedCertData { if !o.EmbedCertData {
return nil return nil
} }
if err := checkExists(FlagCertFile, o.ClientCertificate); err != nil { if err := checkExists("client-certificate", o.ClientCertificate); err != nil {
return err return err
} }
if err := checkExists(FlagKeyFile, o.ClientKey); err != nil { if err := checkExists("client-key", o.ClientKey); err != nil {
return err return err
} }
@ -81,7 +93,7 @@ func (o *ContextOptions) Validate() error {
} }
if o.Current && o.Name != "" { if o.Current && o.Name != "" {
return fmt.Errorf("you cannot specify context and --%s Flag at the same time", FlagCurrent) return errors.New("you cannot specify context and --current Flag at the same time")
} }
// If the user simply wants to change the current context, no further validation is needed // If the user simply wants to change the current context, no further validation is needed
@ -111,14 +123,14 @@ func (o *ClusterOptions) Validate() error {
} }
if o.InsecureSkipTLSVerify && o.CertificateAuthority != "" { if o.InsecureSkipTLSVerify && o.CertificateAuthority != "" {
return fmt.Errorf("you cannot specify a %s and %s mode at the same time", FlagCAFile, FlagInsecure) return errors.New("you cannot specify a certificate-authority and insecure-skip-tls-verify mode at the same time")
} }
if !o.EmbedCAData { if !o.EmbedCAData {
return nil return nil
} }
if err := checkExists(FlagCAFile, o.CertificateAuthority); err != nil { if err := checkExists("certificate-authority", o.CertificateAuthority); err != nil {
return err return err
} }

View File

@ -49,7 +49,7 @@ func (a *AirshipCTLSettings) InitFlags(cmd *cobra.Command) {
defaultAirshipConfigPath := filepath.Join(defaultAirshipConfigDir, config.AirshipConfig) defaultAirshipConfigPath := filepath.Join(defaultAirshipConfigDir, config.AirshipConfig)
flags.StringVar( flags.StringVar(
&a.AirshipConfigPath, &a.AirshipConfigPath,
config.FlagConfigFilePath, "airshipconf",
"", "",
`Path to file for airshipctl configuration. (default "`+defaultAirshipConfigPath+`")`) `Path to file for airshipctl configuration. (default "`+defaultAirshipConfigPath+`")`)