Introduces set_context and get_context operations
Each of these include an option for --current-context that set or retrieves the curret context This patchset mainly creates the cmd/config and pkg/config require additions Also includes a fync getCurrentContext(<CLUSTERTYPE>) in the config pkg that other modules should rely on. Introduces new ErrMissingConfig and ErrConfigFailed types been used by set-context, will decimate through get/ and set/get cluster after this is reviewed. Change-Id: I501483a9db99f33f860eaf329a65bb0209b2aaff
This commit is contained in:
parent
8dd721830b
commit
a480527808
@ -17,6 +17,8 @@ like "airshipctl config set-current-context my-context" `),
|
|||||||
}
|
}
|
||||||
configRootCmd.AddCommand(NewCmdConfigSetCluster(rootSettings))
|
configRootCmd.AddCommand(NewCmdConfigSetCluster(rootSettings))
|
||||||
configRootCmd.AddCommand(NewCmdConfigGetCluster(rootSettings))
|
configRootCmd.AddCommand(NewCmdConfigGetCluster(rootSettings))
|
||||||
|
configRootCmd.AddCommand(NewCmdConfigSetContext(rootSettings))
|
||||||
|
configRootCmd.AddCommand(NewCmdConfigGetContext(rootSettings))
|
||||||
|
|
||||||
return configRootCmd
|
return configRootCmd
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
getClusterLong = (`
|
getClusterLong = (`Display a specific cluster or all defined clusters if no name is provided`)
|
||||||
Gets a specific cluster or all defined clusters if no name is provided`)
|
|
||||||
|
|
||||||
getClusterExample = fmt.Sprintf(`
|
getClusterExample = fmt.Sprintf(`
|
||||||
# List all the clusters airshipctl knows about
|
# List all the clusters airshipctl knows about
|
||||||
@ -44,8 +43,7 @@ func NewCmdConfigGetCluster(rootSettings *environment.AirshipCTLSettings) *cobra
|
|||||||
theCluster := &config.ClusterOptions{}
|
theCluster := &config.ClusterOptions{}
|
||||||
getclustercmd := &cobra.Command{
|
getclustercmd := &cobra.Command{
|
||||||
Use: "get-cluster NAME",
|
Use: "get-cluster NAME",
|
||||||
Short: "Display a specific cluster",
|
Short: getClusterLong,
|
||||||
Long: getClusterLong,
|
|
||||||
Example: getClusterExample,
|
Example: getClusterExample,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
|
107
cmd/config/get_context.go
Normal file
107
cmd/config/get_context.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
getContextLong = (`Display a specific context, the current-context or all defined contexts if no name is provided`)
|
||||||
|
|
||||||
|
getContextExample = fmt.Sprintf(`# List all the contexts airshipctl knows about
|
||||||
|
airshipctl config get-context
|
||||||
|
|
||||||
|
# Display the current context
|
||||||
|
airshipctl config get-context --%v
|
||||||
|
|
||||||
|
# Display a specific Context
|
||||||
|
airshipctl config get-context e2e`,
|
||||||
|
config.FlagCurrentContext)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Context refers to a particular cluster, however it does not specify which of the cluster types
|
||||||
|
// it relates to. Getting explicit information about a particular context will depend
|
||||||
|
// on the ClusterType flag.
|
||||||
|
|
||||||
|
// NewCmdConfigGetContext returns a Command instance for 'config -Context' sub command
|
||||||
|
func NewCmdConfigGetContext(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
|
||||||
|
|
||||||
|
theContext := &config.ContextOptions{}
|
||||||
|
getcontextcmd := &cobra.Command{
|
||||||
|
Use: "get-context NAME",
|
||||||
|
Short: getContextLong,
|
||||||
|
Example: getContextExample,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 1 {
|
||||||
|
theContext.Name = args[0]
|
||||||
|
}
|
||||||
|
return runGetContext(theContext, cmd.OutOrStdout(), rootSettings.Config())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gctxInitFlags(theContext, getcontextcmd)
|
||||||
|
|
||||||
|
return getcontextcmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func gctxInitFlags(o *config.ContextOptions, getcontextcmd *cobra.Command) {
|
||||||
|
getcontextcmd.Flags().BoolVar(&o.CurrentContext, config.FlagCurrentContext, false,
|
||||||
|
config.FlagCurrentContext+" to retrieve the current context entry in airshipctl config")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// runGetContext performs the execution of 'config get-Context' sub command
|
||||||
|
func runGetContext(o *config.ContextOptions, out io.Writer, airconfig *config.Config) error {
|
||||||
|
if o.Name == "" && !o.CurrentContext {
|
||||||
|
return getContexts(out, airconfig)
|
||||||
|
}
|
||||||
|
return getContext(o, out, airconfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContext(o *config.ContextOptions, out io.Writer, airconfig *config.Config) error {
|
||||||
|
cName := o.Name
|
||||||
|
if o.CurrentContext {
|
||||||
|
cName = airconfig.CurrentContext
|
||||||
|
}
|
||||||
|
context, err := airconfig.GetContext(cName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s", context.PrettyString())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContexts(out io.Writer, airconfig *config.Config) error {
|
||||||
|
contexts, err := airconfig.GetContexts()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if contexts == nil {
|
||||||
|
fmt.Fprint(out, "No Contexts found in the configuration.\n")
|
||||||
|
}
|
||||||
|
for _, context := range contexts {
|
||||||
|
fmt.Fprintf(out, "%s", context.PrettyString())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
116
cmd/config/get_context_test.go
Normal file
116
cmd/config/get_context_test.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
|
||||||
|
cmd "opendev.org/airship/airshipctl/cmd/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
"opendev.org/airship/airshipctl/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
currentContextFlag = "--" + config.FlagCurrentContext
|
||||||
|
|
||||||
|
fooContext = "ContextFoo"
|
||||||
|
barContext = "ContextBar"
|
||||||
|
bazContext = "ContextBaz"
|
||||||
|
missingContext = "contextMissing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetContextCmd(t *testing.T) {
|
||||||
|
conf := &config.Config{
|
||||||
|
Contexts: map[string]*config.Context{
|
||||||
|
fooContext: getNamedTestContext(fooContext),
|
||||||
|
barContext: getNamedTestContext(barContext),
|
||||||
|
bazContext: getNamedTestContext(bazContext),
|
||||||
|
},
|
||||||
|
CurrentContext: bazContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := &environment.AirshipCTLSettings{}
|
||||||
|
settings.SetConfig(conf)
|
||||||
|
|
||||||
|
cmdTests := []*testutil.CmdTest{
|
||||||
|
{
|
||||||
|
Name: "get-context",
|
||||||
|
CmdLine: fmt.Sprintf("%s", fooContext),
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "get-all-contexts",
|
||||||
|
CmdLine: fmt.Sprintf("%s %s", fooContext, barContext),
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
},
|
||||||
|
// This is not implemented yet
|
||||||
|
{
|
||||||
|
Name: "get-multiple-contexts",
|
||||||
|
CmdLine: fmt.Sprintf("%s %s", fooContext, barContext),
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "missing",
|
||||||
|
CmdLine: fmt.Sprintf("%s", missingContext),
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
Error: fmt.Errorf("Context %s information was not "+
|
||||||
|
"found in the configuration.", missingContext),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "get-current-context",
|
||||||
|
CmdLine: fmt.Sprintf("%s", currentContextFlag),
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range cmdTests {
|
||||||
|
testutil.RunTest(t, tt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoContextsGetContextCmd(t *testing.T) {
|
||||||
|
settings := &environment.AirshipCTLSettings{}
|
||||||
|
settings.SetConfig(&config.Config{})
|
||||||
|
cmdTest := &testutil.CmdTest{
|
||||||
|
Name: "no-contexts",
|
||||||
|
CmdLine: "",
|
||||||
|
Cmd: cmd.NewCmdConfigGetContext(settings),
|
||||||
|
}
|
||||||
|
testutil.RunTest(t, cmdTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNamedTestContext(contextName string) *config.Context {
|
||||||
|
|
||||||
|
kContext := &kubeconfig.Context{
|
||||||
|
Namespace: "dummy_namespace",
|
||||||
|
AuthInfo: "dummy_user",
|
||||||
|
Cluster: fmt.Sprintf("dummycluster_%s", config.Ephemeral),
|
||||||
|
}
|
||||||
|
|
||||||
|
newContext := &config.Context{
|
||||||
|
NameInKubeconf: fmt.Sprintf("%s_%s", contextName, config.Ephemeral),
|
||||||
|
Manifest: fmt.Sprintf("Manifest_%s", contextName),
|
||||||
|
}
|
||||||
|
newContext.SetKubeContext(kContext)
|
||||||
|
|
||||||
|
return newContext
|
||||||
|
}
|
141
cmd/config/set_context.go
Normal file
141
cmd/config/set_context.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
conferrors "opendev.org/airship/airshipctl/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
setContextLong = (`
|
||||||
|
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.`)
|
||||||
|
|
||||||
|
setContextExample = fmt.Sprintf(`
|
||||||
|
# Create a completely new e2e context entry
|
||||||
|
airshipctl config set-context e2e --%v=kube-system --%v=manifest --%v=auth-info --%v=%v
|
||||||
|
|
||||||
|
# Update the current-context to e2e
|
||||||
|
airshipctl config set-context e2e --%v=true`,
|
||||||
|
config.FlagNamespace,
|
||||||
|
config.FlagManifest,
|
||||||
|
config.FlagAuthInfoName,
|
||||||
|
config.FlagClusterType,
|
||||||
|
config.Target,
|
||||||
|
config.FlagCurrentContext)
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCmdConfigSetContext creates a command object for the "set-context" action, which
|
||||||
|
// defines a new Context airship config.
|
||||||
|
func NewCmdConfigSetContext(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
|
||||||
|
theContext := &config.ContextOptions{}
|
||||||
|
|
||||||
|
setcontextcmd := &cobra.Command{
|
||||||
|
Use: "set-context NAME",
|
||||||
|
Short: "Sets a context entry or updates current-context in the airshipctl config",
|
||||||
|
Long: setContextLong,
|
||||||
|
Example: setContextExample,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
theContext.Name = cmd.Flags().Args()[0]
|
||||||
|
modified, err := runSetContext(theContext, rootSettings.Config())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if modified {
|
||||||
|
fmt.Fprintf(cmd.OutOrStdout(), "Context %q modified.\n", theContext.Name)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(cmd.OutOrStdout(), "Context %q created.\n", theContext.Name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sctxInitFlags(theContext, setcontextcmd)
|
||||||
|
return setcontextcmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func sctxInitFlags(o *config.ContextOptions, setcontextcmd *cobra.Command) {
|
||||||
|
|
||||||
|
setcontextcmd.Flags().BoolVar(&o.CurrentContext, config.FlagCurrentContext, false,
|
||||||
|
config.FlagCurrentContext+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
setcontextcmd.Flags().StringVar(&o.Cluster, config.FlagClusterName, o.Cluster,
|
||||||
|
config.FlagClusterName+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
setcontextcmd.Flags().StringVar(&o.AuthInfo, config.FlagAuthInfoName, o.AuthInfo,
|
||||||
|
config.FlagAuthInfoName+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
setcontextcmd.Flags().StringVar(&o.Manifest, config.FlagManifest, o.Manifest,
|
||||||
|
config.FlagManifest+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
setcontextcmd.Flags().StringVar(&o.Namespace, config.FlagNamespace, o.Namespace,
|
||||||
|
config.FlagNamespace+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
setcontextcmd.Flags().StringVar(&o.ClusterType, config.FlagClusterType, "",
|
||||||
|
config.FlagClusterType+" for the context entry in airshipctl config")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func runSetContext(o *config.ContextOptions, airconfig *config.Config) (bool, error) {
|
||||||
|
contextWasModified := false
|
||||||
|
err := o.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return contextWasModified, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contextIWant := o.Name
|
||||||
|
context, err := airconfig.GetContext(contextIWant)
|
||||||
|
if err != nil {
|
||||||
|
var cerr conferrors.ErrMissingConfig
|
||||||
|
if !errors.As(err, &cerr) {
|
||||||
|
// An error occurred, but it wasn't a "missing" config error.
|
||||||
|
return contextWasModified, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.CurrentContext {
|
||||||
|
return contextWasModified, conferrors.ErrMissingConfig{}
|
||||||
|
}
|
||||||
|
// context didn't exist, create it
|
||||||
|
// ignoring the returned added context
|
||||||
|
airconfig.AddContext(o)
|
||||||
|
} else {
|
||||||
|
// Found the desired Current Context
|
||||||
|
// Lets update it and be done.
|
||||||
|
if o.CurrentContext {
|
||||||
|
airconfig.CurrentContext = o.Name
|
||||||
|
} else {
|
||||||
|
// Context exists, lets update
|
||||||
|
airconfig.ModifyContext(context, o)
|
||||||
|
}
|
||||||
|
contextWasModified = true
|
||||||
|
}
|
||||||
|
// Update configuration file just in time persistence approach
|
||||||
|
if err := airconfig.PersistConfig(); err != nil {
|
||||||
|
// Error that it didnt persist the changes
|
||||||
|
return contextWasModified, conferrors.ErrConfigFailed{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contextWasModified, nil
|
||||||
|
}
|
190
cmd/config/set_context_test.go
Normal file
190
cmd/config/set_context_test.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
"opendev.org/airship/airshipctl/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testUser = "admin@kubernetes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type setContextTest struct {
|
||||||
|
description string
|
||||||
|
config *config.Config
|
||||||
|
args []string
|
||||||
|
flags []string
|
||||||
|
expected string
|
||||||
|
expectedConfig *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigSetContext(t *testing.T) {
|
||||||
|
|
||||||
|
cmdTests := []*testutil.CmdTest{
|
||||||
|
{
|
||||||
|
Name: "config-cmd-set-context-with-help",
|
||||||
|
CmdLine: "--help",
|
||||||
|
Cmd: NewCmdConfigSetContext(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range cmdTests {
|
||||||
|
testutil.RunTest(t, tt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetContext(t *testing.T) {
|
||||||
|
|
||||||
|
conf := config.InitConfig(t)
|
||||||
|
|
||||||
|
tname := "dummycontext"
|
||||||
|
tctype := config.Ephemeral
|
||||||
|
|
||||||
|
expconf := config.InitConfig(t)
|
||||||
|
expconf.Contexts[tname] = config.NewContext()
|
||||||
|
clusterName := config.NewClusterComplexName()
|
||||||
|
clusterName.WithType(tname, tctype)
|
||||||
|
expconf.Contexts[tname].NameInKubeconf = clusterName.Name()
|
||||||
|
expconf.Contexts[tname].Manifest = "edge_cloud"
|
||||||
|
|
||||||
|
expkContext := kubeconfig.NewContext()
|
||||||
|
expkContext.AuthInfo = testUser
|
||||||
|
expkContext.Namespace = "kube-system"
|
||||||
|
expconf.KubeConfig().Contexts[expconf.Contexts[tname].NameInKubeconf] = expkContext
|
||||||
|
|
||||||
|
test := setContextTest{
|
||||||
|
description: "Testing 'airshipctl config set-context' with a new context",
|
||||||
|
config: conf,
|
||||||
|
args: []string{tname},
|
||||||
|
flags: []string{
|
||||||
|
"--" + config.FlagClusterType + "=" + config.Target,
|
||||||
|
"--" + config.FlagAuthInfoName + "=" + testUser,
|
||||||
|
"--" + config.FlagManifest + "=edge_cloud",
|
||||||
|
"--" + config.FlagNamespace + "=kube-system",
|
||||||
|
},
|
||||||
|
expected: `Context "` + tname + `" created.` + "\n",
|
||||||
|
expectedConfig: expconf,
|
||||||
|
}
|
||||||
|
test.run(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetCurrentContext(t *testing.T) {
|
||||||
|
tname := "def_target"
|
||||||
|
conf := config.InitConfig(t)
|
||||||
|
|
||||||
|
expconf := config.InitConfig(t)
|
||||||
|
expconf.CurrentContext = "def_target"
|
||||||
|
|
||||||
|
test := setContextTest{
|
||||||
|
description: "Testing 'airshipctl config set-context' with a new current context",
|
||||||
|
config: conf,
|
||||||
|
args: []string{tname},
|
||||||
|
flags: []string{
|
||||||
|
"--" + config.FlagCurrentContext + "=true",
|
||||||
|
},
|
||||||
|
expected: `Context "` + tname + `" modified.` + "\n",
|
||||||
|
expectedConfig: expconf,
|
||||||
|
}
|
||||||
|
test.run(t)
|
||||||
|
}
|
||||||
|
func TestModifyContext(t *testing.T) {
|
||||||
|
tname := testCluster
|
||||||
|
tctype := config.Ephemeral
|
||||||
|
|
||||||
|
conf := config.InitConfig(t)
|
||||||
|
conf.Contexts[tname] = config.NewContext()
|
||||||
|
|
||||||
|
clusterName := config.NewClusterComplexName()
|
||||||
|
clusterName.WithType(tname, tctype)
|
||||||
|
conf.Contexts[tname].NameInKubeconf = clusterName.Name()
|
||||||
|
kContext := kubeconfig.NewContext()
|
||||||
|
kContext.AuthInfo = testUser
|
||||||
|
conf.KubeConfig().Contexts[clusterName.Name()] = kContext
|
||||||
|
conf.Contexts[tname].SetKubeContext(kContext)
|
||||||
|
|
||||||
|
expconf := config.InitConfig(t)
|
||||||
|
expconf.Contexts[tname] = config.NewContext()
|
||||||
|
expconf.Contexts[tname].NameInKubeconf = clusterName.Name()
|
||||||
|
expkContext := kubeconfig.NewContext()
|
||||||
|
expkContext.AuthInfo = testUser
|
||||||
|
expconf.KubeConfig().Contexts[clusterName.Name()] = expkContext
|
||||||
|
expconf.Contexts[tname].SetKubeContext(expkContext)
|
||||||
|
|
||||||
|
test := setContextTest{
|
||||||
|
description: "Testing 'airshipctl config set-context' with an existing context",
|
||||||
|
config: conf,
|
||||||
|
args: []string{tname},
|
||||||
|
flags: []string{
|
||||||
|
"--" + config.FlagAuthInfoName + "=" + testUser,
|
||||||
|
},
|
||||||
|
expected: `Context "` + tname + `" modified.` + "\n",
|
||||||
|
expectedConfig: expconf,
|
||||||
|
}
|
||||||
|
test.run(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (test setContextTest) run(t *testing.T) {
|
||||||
|
|
||||||
|
// Get the Environment
|
||||||
|
settings := &environment.AirshipCTLSettings{}
|
||||||
|
settings.SetConfig(test.config)
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
cmd := NewCmdConfigSetContext(settings)
|
||||||
|
cmd.SetOutput(buf)
|
||||||
|
cmd.SetArgs(test.args)
|
||||||
|
err := cmd.Flags().Parse(test.flags)
|
||||||
|
require.NoErrorf(t, err, "unexpected error flags args to command: %v, flags: %v", err, test.flags)
|
||||||
|
|
||||||
|
// Execute the Command
|
||||||
|
// Which should Persist the File
|
||||||
|
err = cmd.Execute()
|
||||||
|
require.NoErrorf(t, err, "unexpected error executing command: %v, args: %v, flags: %v", err, test.args, test.flags)
|
||||||
|
|
||||||
|
afterRunConf := settings.Config()
|
||||||
|
|
||||||
|
// Find the Context Created or Modified
|
||||||
|
afterRunContext, err := afterRunConf.GetContext(test.args[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, afterRunContext)
|
||||||
|
|
||||||
|
afterKcontext := afterRunContext.KubeContext()
|
||||||
|
require.NotNil(t, afterKcontext)
|
||||||
|
|
||||||
|
testKcontext := test.expectedConfig.KubeConfig().Contexts[test.expectedConfig.Contexts[test.args[0]].NameInKubeconf]
|
||||||
|
require.NotNil(t, testKcontext)
|
||||||
|
|
||||||
|
assert.EqualValues(t, afterKcontext.AuthInfo, testKcontext.AuthInfo)
|
||||||
|
|
||||||
|
// Test that the Return Message looks correct
|
||||||
|
if len(test.expected) != 0 {
|
||||||
|
assert.EqualValuesf(t, buf.String(), test.expected, "expected %v, but got %v", test.expected, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,9 +5,11 @@ Usage:
|
|||||||
config [command]
|
config [command]
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
get-cluster Display a specific cluster
|
get-cluster Display a specific cluster or all defined clusters if no name is provided
|
||||||
|
get-context Display a specific context, the current-context or all defined contexts if no name is provided
|
||||||
help Help about any command
|
help Help about any command
|
||||||
set-cluster Sets a cluster entry in the airshipctl config
|
set-cluster Sets a cluster entry in the airshipctl config
|
||||||
|
set-context Sets a context entry or updates current-context in the airshipctl config
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-h, --help help for config
|
-h, --help help for config
|
||||||
|
@ -5,9 +5,11 @@ Usage:
|
|||||||
config [command]
|
config [command]
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
get-cluster Display a specific cluster
|
get-cluster Display a specific cluster or all defined clusters if no name is provided
|
||||||
|
get-context Display a specific context, the current-context or all defined contexts if no name is provided
|
||||||
help Help about any command
|
help Help about any command
|
||||||
set-cluster Sets a cluster entry in the airshipctl config
|
set-cluster Sets a cluster entry in the airshipctl config
|
||||||
|
set-context Sets a context entry or updates current-context in the airshipctl config
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-h, --help help for config
|
-h, --help help for config
|
||||||
|
23
cmd/config/testdata/TestConfigSetContextGoldenOutput/config-cmd-set-context-with-help.golden
vendored
Normal file
23
cmd/config/testdata/TestConfigSetContextGoldenOutput/config-cmd-set-context-with-help.golden
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
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:
|
||||||
|
set-context NAME [flags]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
# Create a completely new e2e context entry
|
||||||
|
airshipctl config set-context e2e --namespace=kube-system --manifest=manifest --user=auth-info --cluster-type=target
|
||||||
|
|
||||||
|
# Update the current-context to e2e
|
||||||
|
airshipctl config set-context e2e --current-context=true
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
--cluster string cluster for the context entry in airshipctl config
|
||||||
|
--cluster-type string cluster-type for the context entry in airshipctl config
|
||||||
|
--current-context current-context for the context entry in airshipctl config
|
||||||
|
-h, --help help for set-context
|
||||||
|
--manifest string manifest for the context entry in airshipctl config
|
||||||
|
--namespace string namespace for the context entry in airshipctl config
|
||||||
|
--user string user for the context entry in airshipctl config
|
27
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-all-contexts.golden
vendored
Normal file
27
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-all-contexts.golden
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Context: ContextBar
|
||||||
|
context-kubeconf: ContextBar_ephemeral
|
||||||
|
manifest: Manifest_ContextBar
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
||||||
|
Context: ContextBaz
|
||||||
|
context-kubeconf: ContextBaz_ephemeral
|
||||||
|
manifest: Manifest_ContextBaz
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
||||||
|
Context: ContextFoo
|
||||||
|
context-kubeconf: ContextFoo_ephemeral
|
||||||
|
manifest: Manifest_ContextFoo
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
9
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-context.golden
vendored
Normal file
9
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-context.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Context: ContextFoo
|
||||||
|
context-kubeconf: ContextFoo_ephemeral
|
||||||
|
manifest: Manifest_ContextFoo
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
9
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-current-context.golden
vendored
Normal file
9
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-current-context.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Context: ContextBaz
|
||||||
|
context-kubeconf: ContextBaz_ephemeral
|
||||||
|
manifest: Manifest_ContextBaz
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
27
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-multiple-contexts.golden
vendored
Normal file
27
cmd/config/testdata/TestGetContextCmdGoldenOutput/get-multiple-contexts.golden
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Context: ContextBar
|
||||||
|
context-kubeconf: ContextBar_ephemeral
|
||||||
|
manifest: Manifest_ContextBar
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
||||||
|
Context: ContextBaz
|
||||||
|
context-kubeconf: ContextBaz_ephemeral
|
||||||
|
manifest: Manifest_ContextBaz
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
||||||
|
Context: ContextFoo
|
||||||
|
context-kubeconf: ContextFoo_ephemeral
|
||||||
|
manifest: Manifest_ContextFoo
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
|
18
cmd/config/testdata/TestGetContextCmdGoldenOutput/missing.golden
vendored
Normal file
18
cmd/config/testdata/TestGetContextCmdGoldenOutput/missing.golden
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Error: Missing configuration
|
||||||
|
Usage:
|
||||||
|
get-context NAME [flags]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
# List all the contexts airshipctl knows about
|
||||||
|
airshipctl config get-context
|
||||||
|
|
||||||
|
# Display the current context
|
||||||
|
airshipctl config get-context --current-context
|
||||||
|
|
||||||
|
# Display a specific Context
|
||||||
|
airshipctl config get-context e2e
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
--current-context current-context to retrieve the current context entry in airshipctl config
|
||||||
|
-h, --help help for get-context
|
||||||
|
|
0
cmd/config/testdata/TestNoContextsGetContextCmdGoldenOutput/no-contexts.golden
vendored
Normal file
0
cmd/config/testdata/TestNoContextsGetContextCmdGoldenOutput/no-contexts.golden
vendored
Normal file
@ -47,3 +47,18 @@ func (o *ClusterOptions) Validate() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ContextOptions) Validate() error {
|
||||||
|
if len(o.Name) == 0 {
|
||||||
|
return errors.New("you must specify a non-empty context name")
|
||||||
|
}
|
||||||
|
// Expect ClusterType only when this is not setting currentContext
|
||||||
|
if o.ClusterType != "" {
|
||||||
|
err := ValidClusterType(o.ClusterType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO Manifest, Cluster could be validated against the existing config maps
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidate(t *testing.T) {
|
func TestValidateCluster(t *testing.T) {
|
||||||
co := DummyClusterOptions()
|
co := DummyClusterOptions()
|
||||||
|
|
||||||
// Assert that the initial dummy config is valid
|
// Assert that the initial dummy config is valid
|
||||||
@ -61,3 +61,11 @@ func TestValidate(t *testing.T) {
|
|||||||
err = co.Validate()
|
err = co.Validate()
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateContext(t *testing.T) {
|
||||||
|
co := DummyContextOptions()
|
||||||
|
// Valid Data case
|
||||||
|
err := co.Validate()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -8,3 +8,13 @@ type ClusterOptions struct {
|
|||||||
CertificateAuthority string
|
CertificateAuthority string
|
||||||
EmbedCAData bool
|
EmbedCAData bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContextOptions struct {
|
||||||
|
Name string
|
||||||
|
ClusterType string
|
||||||
|
CurrentContext bool
|
||||||
|
Cluster string
|
||||||
|
AuthInfo string
|
||||||
|
Manifest string
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
|
|
||||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
|
||||||
|
conferrors "opendev.org/airship/airshipctl/pkg/errors"
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ func (c *Config) reconcileConfig() error {
|
|||||||
|
|
||||||
// I changed things during the reconciliation
|
// I changed things during the reconciliation
|
||||||
// Lets reflect them in the config files
|
// Lets reflect them in the config files
|
||||||
// Specially useful if the cnofig is loaded during a get operation
|
// Specially useful if the config is loaded during a get operation
|
||||||
// If it was a Set this would have happened eventually any way
|
// If it was a Set this would have happened eventually any way
|
||||||
if persistIt {
|
if persistIt {
|
||||||
return c.PersistConfig()
|
return c.PersistConfig()
|
||||||
@ -211,6 +212,7 @@ func (c *Config) reconcileContexts(updatedClusterNames map[string]string) {
|
|||||||
}
|
}
|
||||||
// Make sure the name matches
|
// Make sure the name matches
|
||||||
c.Contexts[key].NameInKubeconf = context.Cluster
|
c.Contexts[key].NameInKubeconf = context.Cluster
|
||||||
|
c.Contexts[key].SetKubeContext(context)
|
||||||
|
|
||||||
// What about if a Context refers to a properly named cluster
|
// What about if a Context refers to a properly named cluster
|
||||||
// that does not exist in airship config
|
// that does not exist in airship config
|
||||||
@ -267,8 +269,6 @@ func (c *Config) reconcileCurrentContext() {
|
|||||||
c.kubeConfig.CurrentContext = c.CurrentContext
|
c.kubeConfig.CurrentContext = c.CurrentContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.kubeConfig.CurrentContext = ""
|
|
||||||
c.CurrentContext = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by users of the config to make sure that they have
|
// This is called by users of the config to make sure that they have
|
||||||
@ -370,7 +370,6 @@ func (c *Config) KubeConfig() *kubeconfig.Config {
|
|||||||
return c.kubeConfig
|
return c.kubeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// This might be changed later to be generalized
|
|
||||||
func (c *Config) ClusterNames() []string {
|
func (c *Config) ClusterNames() []string {
|
||||||
names := []string{}
|
names := []string{}
|
||||||
for k := range c.Clusters {
|
for k := range c.Clusters {
|
||||||
@ -378,7 +377,15 @@ func (c *Config) ClusterNames() []string {
|
|||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
return names
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ContextNames() []string {
|
||||||
|
names := []string{}
|
||||||
|
for k := range c.Contexts {
|
||||||
|
names = append(names, k)
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get A Cluster
|
// Get A Cluster
|
||||||
@ -476,12 +483,117 @@ func (c *Config) GetClusters() ([]*Cluster, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
clusters = append(clusters, cluster)
|
clusters = append(clusters, cluster)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clusters, nil
|
return clusters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Context Operations from Config point of view
|
||||||
|
// Get Context
|
||||||
|
func (c *Config) GetContext(cName string) (*Context, error) {
|
||||||
|
context, exists := c.Contexts[cName]
|
||||||
|
if !exists {
|
||||||
|
return nil, conferrors.ErrMissingConfig{}
|
||||||
|
}
|
||||||
|
return context, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetContexts() ([]*Context, error) {
|
||||||
|
contexts := []*Context{}
|
||||||
|
// Given that we change the testing metholdogy
|
||||||
|
// The ordered names are no longer required
|
||||||
|
for _, cName := range c.ContextNames() {
|
||||||
|
context, err := c.GetContext(cName)
|
||||||
|
if err == nil {
|
||||||
|
contexts = append(contexts, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contexts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) AddContext(theContext *ContextOptions) *Context {
|
||||||
|
// Create the new Airship config context
|
||||||
|
nContext := NewContext()
|
||||||
|
c.Contexts[theContext.Name] = nContext
|
||||||
|
// Create a new Kubeconfig Context object as well
|
||||||
|
kContext := kubeconfig.NewContext()
|
||||||
|
nContext.NameInKubeconf = theContext.Name
|
||||||
|
contextName := NewClusterComplexName()
|
||||||
|
contextName.WithType(theContext.Name, theContext.ClusterType)
|
||||||
|
|
||||||
|
nContext.SetKubeContext(kContext)
|
||||||
|
c.KubeConfig().Contexts[theContext.Name] = kContext
|
||||||
|
|
||||||
|
// Ok , I have initialized structs for the Context information
|
||||||
|
// We can use Modify to populate the correct information
|
||||||
|
c.ModifyContext(nContext, theContext)
|
||||||
|
return nContext
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ModifyContext(context *Context, theContext *ContextOptions) {
|
||||||
|
kContext := context.KubeContext()
|
||||||
|
if kContext == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if theContext.Cluster != "" {
|
||||||
|
kContext.Cluster = theContext.Cluster
|
||||||
|
}
|
||||||
|
if theContext.AuthInfo != "" {
|
||||||
|
kContext.AuthInfo = theContext.AuthInfo
|
||||||
|
}
|
||||||
|
if theContext.Manifest != "" {
|
||||||
|
context.Manifest = theContext.Manifest
|
||||||
|
}
|
||||||
|
if theContext.Namespace != "" {
|
||||||
|
kContext.Namespace = theContext.Namespace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentContext methods Returns the appropriate information for the current context
|
||||||
|
// Current Context holds labels for the approriate config objects
|
||||||
|
// Cluster is the name of the cluster for this context
|
||||||
|
// ClusterType is the name of the clustertype for this context, it should be a flag we pass to it??
|
||||||
|
// AuthInfo is the name of the authInfo for this context
|
||||||
|
// Manifest is the default manifest to be use with this context
|
||||||
|
// Purpose for this method is simplifying the current context information
|
||||||
|
func (c *Config) GetCurrentContext() (*Context, error) {
|
||||||
|
if err := c.EnsureComplete(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
currentContext, err := c.GetContext(c.CurrentContext)
|
||||||
|
if err != nil {
|
||||||
|
// this should not happen since Ensure Complete checks for this
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return currentContext, nil
|
||||||
|
}
|
||||||
|
func (c *Config) CurrentContextCluster() (*Cluster, error) {
|
||||||
|
currentContext, err := c.GetCurrentContext()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Clusters[currentContext.KubeContext().Cluster].ClusterTypes[currentContext.ClusterType()], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) CurrentContextAuthInfo() (*AuthInfo, error) {
|
||||||
|
currentContext, err := c.GetCurrentContext()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.AuthInfos[currentContext.KubeContext().AuthInfo], nil
|
||||||
|
}
|
||||||
|
func (c *Config) CurrentContextManifest() (*Manifest, error) {
|
||||||
|
currentContext, err := c.GetCurrentContext()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Manifests[currentContext.Manifest], nil
|
||||||
|
}
|
||||||
|
|
||||||
// Purge removes the config file
|
// Purge removes the config file
|
||||||
func (c *Config) Purge() error {
|
func (c *Config) Purge() error {
|
||||||
//configFile := c.ConfigFile()
|
//configFile := c.ConfigFile()
|
||||||
@ -550,15 +662,44 @@ func (c *Context) Equal(d *Context) bool {
|
|||||||
return d == c
|
return d == c
|
||||||
}
|
}
|
||||||
return c.NameInKubeconf == d.NameInKubeconf &&
|
return c.NameInKubeconf == d.NameInKubeconf &&
|
||||||
c.Manifest == d.Manifest
|
c.Manifest == d.Manifest &&
|
||||||
|
c.kContext == d.kContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) String() string {
|
func (c *Context) String() string {
|
||||||
yaml, err := yaml.Marshal(&c)
|
cyaml, err := yaml.Marshal(&c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return string(yaml)
|
kcluster := c.KubeContext()
|
||||||
|
kyaml, err := yaml.Marshal(&kcluster)
|
||||||
|
if err != nil {
|
||||||
|
return string(cyaml)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s\n%s", string(cyaml), string(kyaml))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) PrettyString() string {
|
||||||
|
clusterName := NewClusterComplexName()
|
||||||
|
clusterName.FromName(c.NameInKubeconf)
|
||||||
|
|
||||||
|
return fmt.Sprintf("Context: %s\n%s\n",
|
||||||
|
clusterName.ClusterName(), c.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) KubeContext() *kubeconfig.Context {
|
||||||
|
return c.kContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) SetKubeContext(kc *kubeconfig.Context) {
|
||||||
|
c.kContext = kc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) ClusterType() string {
|
||||||
|
clusterName := NewClusterComplexName()
|
||||||
|
clusterName.FromName(c.NameInKubeconf)
|
||||||
|
return clusterName.ClusterType()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthInfo functions
|
// AuthInfo functions
|
||||||
@ -695,3 +836,11 @@ func KClusterString(kCluster *kubeconfig.Cluster) string {
|
|||||||
|
|
||||||
return string(yaml)
|
return string(yaml)
|
||||||
}
|
}
|
||||||
|
func KContextString(kContext *kubeconfig.Context) string {
|
||||||
|
yaml, err := yaml.Marshal(&kContext)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(yaml)
|
||||||
|
}
|
||||||
|
@ -232,11 +232,6 @@ func TestPurge(t *testing.T) {
|
|||||||
assert.Falsef(t, os.IsExist(err), "Purge failed to remove file at %v", config.LoadedConfigPath())
|
assert.Falsef(t, os.IsExist(err), "Purge failed to remove file at %v", config.LoadedConfigPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClusterNames(t *testing.T) {
|
|
||||||
conf := InitConfig(t)
|
|
||||||
expected := []string{"def", "onlyinkubeconf", "wrongonlyinconfig", "wrongonlyinkubeconf"}
|
|
||||||
assert.EqualValues(t, expected, conf.ClusterNames())
|
|
||||||
}
|
|
||||||
func TestKClusterString(t *testing.T) {
|
func TestKClusterString(t *testing.T) {
|
||||||
conf := InitConfig(t)
|
conf := InitConfig(t)
|
||||||
kClusters := conf.KubeConfig().Clusters
|
kClusters := conf.KubeConfig().Clusters
|
||||||
@ -245,6 +240,14 @@ func TestKClusterString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.EqualValues(t, KClusterString(nil), "null\n")
|
assert.EqualValues(t, KClusterString(nil), "null\n")
|
||||||
}
|
}
|
||||||
|
func TestKContextString(t *testing.T) {
|
||||||
|
conf := InitConfig(t)
|
||||||
|
kContexts := conf.KubeConfig().Contexts
|
||||||
|
for kCtx := range kContexts {
|
||||||
|
assert.NotEmpty(t, KContextString(kContexts[kCtx]))
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, KClusterString(nil), "null\n")
|
||||||
|
}
|
||||||
func TestComplexName(t *testing.T) {
|
func TestComplexName(t *testing.T) {
|
||||||
cName := "aCluster"
|
cName := "aCluster"
|
||||||
ctName := Ephemeral
|
ctName := Ephemeral
|
||||||
@ -372,3 +375,25 @@ func TestReconcileClusters(t *testing.T) {
|
|||||||
// Check that the "stragglers" were removed from the airshipconfig
|
// Check that the "stragglers" were removed from the airshipconfig
|
||||||
assert.NotContains(t, testConfig.Clusters, "straggler")
|
assert.NotContains(t, testConfig.Clusters, "straggler")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetContexts(t *testing.T) {
|
||||||
|
conf := InitConfig(t)
|
||||||
|
contexts, err := conf.GetContexts()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, contexts, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetContext(t *testing.T) {
|
||||||
|
conf := InitConfig(t)
|
||||||
|
context, err := conf.GetContext("def_ephemeral")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Test Positives
|
||||||
|
assert.EqualValues(t, context.NameInKubeconf, "def_ephemeral")
|
||||||
|
assert.EqualValues(t, context.KubeContext().Cluster, "def_ephemeral")
|
||||||
|
|
||||||
|
// Test Wrong Cluster
|
||||||
|
_, err = conf.GetContext("unknown")
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -28,23 +28,24 @@ const (
|
|||||||
|
|
||||||
// Constants defining CLI flags
|
// Constants defining CLI flags
|
||||||
const (
|
const (
|
||||||
|
FlagAPIServer = "server"
|
||||||
|
FlagAuthInfoName = "user"
|
||||||
|
FlagBearerToken = "token"
|
||||||
|
FlagCAFile = "certificate-authority"
|
||||||
|
FlagCertFile = "client-certificate"
|
||||||
FlagClusterName = "cluster"
|
FlagClusterName = "cluster"
|
||||||
FlagClusterType = "cluster-type"
|
FlagClusterType = "cluster-type"
|
||||||
FlagAuthInfoName = "user"
|
|
||||||
FlagContext = "context"
|
FlagContext = "context"
|
||||||
|
FlagCurrentContext = "current-context"
|
||||||
FlagConfigFilePath = AirshipConfigEnv
|
FlagConfigFilePath = AirshipConfigEnv
|
||||||
FlagNamespace = "namespace"
|
|
||||||
FlagAPIServer = "server"
|
|
||||||
FlagInsecure = "insecure-skip-tls-verify"
|
|
||||||
FlagCertFile = "client-certificate"
|
|
||||||
FlagKeyFile = "client-key"
|
|
||||||
FlagCAFile = "certificate-authority"
|
|
||||||
FlagEmbedCerts = "embed-certs"
|
FlagEmbedCerts = "embed-certs"
|
||||||
FlagBearerToken = "token"
|
|
||||||
FlagImpersonate = "as"
|
FlagImpersonate = "as"
|
||||||
FlagImpersonateGroup = "as-group"
|
FlagImpersonateGroup = "as-group"
|
||||||
FlagUsername = "username"
|
FlagInsecure = "insecure-skip-tls-verify"
|
||||||
|
FlagKeyFile = "client-key"
|
||||||
|
FlagManifest = "manifest"
|
||||||
|
FlagNamespace = "namespace"
|
||||||
FlagPassword = "password"
|
FlagPassword = "password"
|
||||||
FlagTimeout = "request-timeout"
|
FlagTimeout = "request-timeout"
|
||||||
FlagManifest = "manifest"
|
FlagUsername = "username"
|
||||||
)
|
)
|
||||||
|
@ -60,6 +60,12 @@ func DummyContext() *Context {
|
|||||||
c := NewContext()
|
c := NewContext()
|
||||||
c.NameInKubeconf = "dummy_cluster"
|
c.NameInKubeconf = "dummy_cluster"
|
||||||
c.Manifest = "dummy_manifest"
|
c.Manifest = "dummy_manifest"
|
||||||
|
context := kubeconfig.NewContext()
|
||||||
|
context.Namespace = "dummy_namespace"
|
||||||
|
context.AuthInfo = "dummy_user"
|
||||||
|
context.Cluster = "dummycluster_ephemeral"
|
||||||
|
c.SetKubeContext(context)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +150,17 @@ func DummyClusterOptions() *ClusterOptions {
|
|||||||
return co
|
return co
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DummyContextOptions() *ContextOptions {
|
||||||
|
co := &ContextOptions{}
|
||||||
|
co.Name = "dummy_context"
|
||||||
|
co.Manifest = "dummy_manifest"
|
||||||
|
co.AuthInfo = "dummy_user"
|
||||||
|
co.CurrentContext = false
|
||||||
|
co.Namespace = "dummy_namespace"
|
||||||
|
|
||||||
|
return co
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testConfigYAML = `apiVersion: airshipit.org/v1alpha1
|
testConfigYAML = `apiVersion: airshipit.org/v1alpha1
|
||||||
clusters:
|
clusters:
|
||||||
|
5
pkg/config/testdata/context-string.yaml
vendored
5
pkg/config/testdata/context-string.yaml
vendored
@ -1,2 +1,7 @@
|
|||||||
context-kubeconf: dummy_cluster
|
context-kubeconf: dummy_cluster
|
||||||
manifest: dummy_manifest
|
manifest: dummy_manifest
|
||||||
|
|
||||||
|
LocationOfOrigin: ""
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
namespace: dummy_namespace
|
||||||
|
user: dummy_user
|
||||||
|
@ -97,15 +97,18 @@ type Modules struct {
|
|||||||
Dummy string `json:"dummy-for-tests"`
|
Dummy string `json:"dummy-for-tests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster),
|
// Context is a tuple of references to a cluster (how do I communicate with a kubernetes context),
|
||||||
// a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)
|
// a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)
|
||||||
type Context struct {
|
type Context struct {
|
||||||
// Context name in kubeconf. Should include a clustername following the naming conventions for airshipctl
|
// Context name in kubeconf
|
||||||
// <clustername>_<clustertype>
|
|
||||||
NameInKubeconf string `json:"context-kubeconf"`
|
NameInKubeconf string `json:"context-kubeconf"`
|
||||||
|
|
||||||
// Manifest is the default manifest to be use with this context
|
// Manifest is the default manifest to be use with this context
|
||||||
// +optional
|
// +optional
|
||||||
Manifest string `json:"manifest,omitempty"`
|
Manifest string `json:"manifest,omitempty"`
|
||||||
|
|
||||||
|
// Kubeconfig Context Object
|
||||||
|
kContext *kubeconfig.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthInfo struct {
|
type AuthInfo struct {
|
||||||
|
@ -1,11 +1,24 @@
|
|||||||
package errors
|
package errors
|
||||||
|
|
||||||
|
// AirshipError is the base error type
|
||||||
|
// used to create extended error types
|
||||||
|
// in other airshipctl packages.
|
||||||
|
type AirshipError struct {
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error function implments the golang
|
||||||
|
// error interface
|
||||||
|
func (ae *AirshipError) Error() string {
|
||||||
|
return ae.Message
|
||||||
|
}
|
||||||
|
|
||||||
// ErrNotImplemented returned for not implemented features
|
// ErrNotImplemented returned for not implemented features
|
||||||
type ErrNotImplemented struct {
|
type ErrNotImplemented struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrNotImplemented) Error() string {
|
func (e ErrNotImplemented) Error() string {
|
||||||
return "Error. Not implemented"
|
return "Not implemented"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrWrongConfig returned in case of incorrect configuration
|
// ErrWrongConfig returned in case of incorrect configuration
|
||||||
@ -13,5 +26,21 @@ type ErrWrongConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrWrongConfig) Error() string {
|
func (e ErrWrongConfig) Error() string {
|
||||||
return "Error. Wrong configuration"
|
return "Wrong configuration"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMissingConfig returned in case of missing configuration
|
||||||
|
type ErrMissingConfig struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMissingConfig) Error() string {
|
||||||
|
return "Missing configuration"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrConfigFailed returned in case of failure during configuration
|
||||||
|
type ErrConfigFailed struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrConfigFailed) Error() string {
|
||||||
|
return "Configuration failed to complete."
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user