Remove clusters, users, reconcilation and config import
All of these entities are no longer required and should be deleted. Change-Id: Id4776efe668265df6961a38ce984b8ac37b27097 Signed-off-by: Ruslan Aliev <raliev@mirantis.com> Relates-To: #327
This commit is contained in:
parent
d87eea6544
commit
5d52339bd6
@ -82,8 +82,6 @@ func TestNewClusterStatusCmd(t *testing.T) {
|
||||
func clusterStatusTestSettings() config.Factory {
|
||||
return func() (*config.Config, error) {
|
||||
return &config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": nil},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": nil},
|
||||
Contexts: map[string]*config.Context{
|
||||
"testContext": {Manifest: "testManifest"},
|
||||
},
|
||||
|
@ -34,7 +34,6 @@ func NewConfigCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
configRootCmd.AddCommand(NewGetManagementConfigCommand(cfgFactory))
|
||||
configRootCmd.AddCommand(NewSetManagementConfigCommand(cfgFactory))
|
||||
|
||||
configRootCmd.AddCommand(NewImportCommand(cfgFactory))
|
||||
configRootCmd.AddCommand(NewUseContextCommand(cfgFactory))
|
||||
|
||||
configRootCmd.AddCommand(NewGetManifestCommand(cfgFactory))
|
||||
|
@ -20,8 +20,6 @@ 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/testutil"
|
||||
@ -94,17 +92,10 @@ func TestNoContextsGetContextCmd(t *testing.T) {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
)
|
||||
|
||||
const (
|
||||
useImportLong = `
|
||||
Merge the clusters, contexts, and users from an existing kubeConfig file into the airshipctl config file.
|
||||
`
|
||||
|
||||
useImportExample = `
|
||||
# Import from a kubeConfig file"
|
||||
airshipctl config import $HOME/.kube/config
|
||||
`
|
||||
)
|
||||
|
||||
// NewImportCommand creates a command that merges clusters, contexts, and
|
||||
// users from a kubeConfig file into the airshipctl config file.
|
||||
func NewImportCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "import <kubeConfig>",
|
||||
Short: "Merge information from a kubernetes config file",
|
||||
Long: useImportLong[1:],
|
||||
Example: useImportExample,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := cfgFactory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeConfigPath := args[0]
|
||||
err = cfg.ImportFromKubeConfig(kubeConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Updated airship config with content imported from %q.\n", kubeConfigPath)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
|
||||
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 (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
cmd "opendev.org/airship/airshipctl/cmd/config"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
func TestConfigImport(t *testing.T) {
|
||||
settings := func() (*config.Config, error) {
|
||||
return testutil.DummyConfig(), nil
|
||||
}
|
||||
|
||||
cmdTests := []*testutil.CmdTest{
|
||||
{
|
||||
Name: "config-import-with-help",
|
||||
CmdLine: "--help",
|
||||
Cmd: cmd.NewImportCommand(nil),
|
||||
},
|
||||
{
|
||||
Name: "config-import-no-args",
|
||||
CmdLine: "",
|
||||
Cmd: cmd.NewImportCommand(settings),
|
||||
Error: errors.New("accepts 1 arg(s), received 0"),
|
||||
},
|
||||
{
|
||||
Name: "config-import-file-does-not-exist",
|
||||
CmdLine: "foo",
|
||||
Cmd: cmd.NewImportCommand(settings),
|
||||
Error: errors.New("stat foo: no such file or directory"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cmdTests {
|
||||
testutil.RunTest(t, tt)
|
||||
}
|
||||
}
|
@ -32,10 +32,7 @@ Create or modify a context in the airshipctl config files.
|
||||
setContextExample = `
|
||||
# Create a new context named "exampleContext"
|
||||
airshipctl config set-context exampleContext \
|
||||
--namespace=kube-system \
|
||||
--manifest=exampleManifest \
|
||||
--user=exampleUser
|
||||
--cluster-type=target
|
||||
--encryption-config=exampleEncryptionConfig
|
||||
|
||||
# Update the manifest of the current-context
|
||||
@ -91,18 +88,6 @@ func NewSetContextCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
func addSetContextFlags(o *config.ContextOptions, cmd *cobra.Command) {
|
||||
flags := cmd.Flags()
|
||||
|
||||
flags.StringVar(
|
||||
&o.Cluster,
|
||||
"cluster",
|
||||
"",
|
||||
"set the cluster for the specified context")
|
||||
|
||||
flags.StringVar(
|
||||
&o.AuthInfo,
|
||||
"user",
|
||||
"",
|
||||
"set the user for the specified context")
|
||||
|
||||
flags.StringVar(
|
||||
&o.Manifest,
|
||||
"manifest",
|
||||
@ -115,12 +100,6 @@ func addSetContextFlags(o *config.ContextOptions, cmd *cobra.Command) {
|
||||
"",
|
||||
"set the encryption config for the specified context")
|
||||
|
||||
flags.StringVar(
|
||||
&o.Namespace,
|
||||
"namespace",
|
||||
"",
|
||||
"set the namespace for the specified context")
|
||||
|
||||
flags.StringVar(
|
||||
&o.ClusterType,
|
||||
"cluster-type",
|
||||
|
@ -30,11 +30,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
testUser = "admin@kubernetes"
|
||||
defaultManifest = "edge_cloud"
|
||||
defaultNamespace = "kube-system"
|
||||
testManifest = "test_manifest"
|
||||
testEncryptionConfig = "test_encryption_config"
|
||||
defaultManifest = "edge_cloud"
|
||||
testManifest = "test_manifest"
|
||||
)
|
||||
|
||||
type setContextTest struct {
|
||||
@ -86,9 +84,7 @@ func TestSetContext(t *testing.T) {
|
||||
contextName: "dummycontext",
|
||||
flags: []string{
|
||||
"--cluster-type=target",
|
||||
"--user=" + testUser,
|
||||
"--manifest=" + defaultManifest,
|
||||
"--namespace=" + defaultNamespace,
|
||||
"--encryption-config=" + testEncryptionConfig,
|
||||
},
|
||||
givenConfig: given,
|
||||
@ -153,9 +149,6 @@ func (test setContextTest) run(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, afterRunContext)
|
||||
|
||||
afterKcontext := afterRunContext.KubeContext()
|
||||
require.NotNil(t, afterKcontext)
|
||||
|
||||
if test.manifest != "" {
|
||||
assert.EqualValues(t, afterRunContext.Manifest, test.manifest)
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ Available Commands:
|
||||
get-management-config View a management config or all management configs defined in the airshipctl config
|
||||
get-manifest Get a manifest information from the airshipctl config
|
||||
help Help about any command
|
||||
import Merge information from a kubernetes config file
|
||||
init Generate initial configuration files for airshipctl
|
||||
set-context Manage contexts
|
||||
set-encryption-config Manage encryption configs in airship config
|
||||
|
@ -1,13 +0,0 @@
|
||||
Error: stat foo: no such file or directory
|
||||
Usage:
|
||||
import <kubeConfig> [flags]
|
||||
|
||||
Examples:
|
||||
|
||||
# Import from a kubeConfig file"
|
||||
airshipctl config import $HOME/.kube/config
|
||||
|
||||
|
||||
Flags:
|
||||
-h, --help help for import
|
||||
|
@ -1,13 +0,0 @@
|
||||
Error: accepts 1 arg(s), received 0
|
||||
Usage:
|
||||
import <kubeConfig> [flags]
|
||||
|
||||
Examples:
|
||||
|
||||
# Import from a kubeConfig file"
|
||||
airshipctl config import $HOME/.kube/config
|
||||
|
||||
|
||||
Flags:
|
||||
-h, --help help for import
|
||||
|
@ -1,13 +0,0 @@
|
||||
Merge the clusters, contexts, and users from an existing kubeConfig file into the airshipctl config file.
|
||||
|
||||
Usage:
|
||||
import <kubeConfig> [flags]
|
||||
|
||||
Examples:
|
||||
|
||||
# Import from a kubeConfig file"
|
||||
airshipctl config import $HOME/.kube/config
|
||||
|
||||
|
||||
Flags:
|
||||
-h, --help help for import
|
@ -6,10 +6,7 @@ Examples:
|
||||
|
||||
# Create a new context named "exampleContext"
|
||||
airshipctl config set-context exampleContext \
|
||||
--namespace=kube-system \
|
||||
--manifest=exampleManifest \
|
||||
--user=exampleUser
|
||||
--cluster-type=target
|
||||
--encryption-config=exampleEncryptionConfig
|
||||
|
||||
# Update the manifest of the current-context
|
||||
@ -19,12 +16,9 @@ airshipctl config set-context \
|
||||
|
||||
|
||||
Flags:
|
||||
--cluster string set the cluster for the specified context
|
||||
--cluster-type string set the cluster-type for the specified context
|
||||
--current update the current context
|
||||
--encryption-config string set the encryption config for the specified context
|
||||
-h, --help help for set-context
|
||||
--manifest string set the manifest for the specified context
|
||||
--namespace string set the namespace for the specified context
|
||||
--user string set the user for the specified context
|
||||
|
||||
|
@ -7,10 +7,7 @@ Examples:
|
||||
|
||||
# Create a new context named "exampleContext"
|
||||
airshipctl config set-context exampleContext \
|
||||
--namespace=kube-system \
|
||||
--manifest=exampleManifest \
|
||||
--user=exampleUser
|
||||
--cluster-type=target
|
||||
--encryption-config=exampleEncryptionConfig
|
||||
|
||||
# Update the manifest of the current-context
|
||||
@ -20,11 +17,8 @@ airshipctl config set-context \
|
||||
|
||||
|
||||
Flags:
|
||||
--cluster string set the cluster for the specified context
|
||||
--cluster-type string set the cluster-type for the specified context
|
||||
--current update the current context
|
||||
--encryption-config string set the encryption config for the specified context
|
||||
-h, --help help for set-context
|
||||
--manifest string set the manifest for the specified context
|
||||
--namespace string set the namespace for the specified context
|
||||
--user string set the user for the specified context
|
||||
|
@ -1,30 +1,18 @@
|
||||
Context: ContextBar
|
||||
contextKubeconf: ContextBar_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextBar
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
Context: ContextBaz
|
||||
contextKubeconf: ContextBaz_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextBaz
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
Context: ContextFoo
|
||||
contextKubeconf: ContextFoo_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextFoo
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
|
@ -1,10 +1,6 @@
|
||||
Context: ContextFoo
|
||||
contextKubeconf: ContextFoo_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextFoo
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
|
@ -1,10 +1,6 @@
|
||||
Context: ContextBaz
|
||||
contextKubeconf: ContextBaz_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextBaz
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
|
@ -1,30 +1,18 @@
|
||||
Context: ContextBar
|
||||
contextKubeconf: ContextBar_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextBar
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
Context: ContextBaz
|
||||
contextKubeconf: ContextBaz_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextBaz
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
Context: ContextFoo
|
||||
contextKubeconf: ContextFoo_ephemeral
|
||||
managementConfiguration: ""
|
||||
manifest: Manifest_ContextFoo
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummycluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
||||
|
||||
|
@ -27,7 +27,6 @@ Manage the airshipctl config file
|
||||
* [airshipctl config get-encryption-config](airshipctl_config_get-encryption-config.md) - Get an encryption config information from the airshipctl config
|
||||
* [airshipctl config get-management-config](airshipctl_config_get-management-config.md) - View a management config or all management configs defined in the airshipctl config
|
||||
* [airshipctl config get-manifest](airshipctl_config_get-manifest.md) - Get a manifest information from the airshipctl config
|
||||
* [airshipctl config import](airshipctl_config_import.md) - Merge information from a kubernetes config file
|
||||
* [airshipctl config init](airshipctl_config_init.md) - Generate initial configuration files for airshipctl
|
||||
* [airshipctl config set-context](airshipctl_config_set-context.md) - Manage contexts
|
||||
* [airshipctl config set-encryption-config](airshipctl_config_set-encryption-config.md) - Manage encryption configs in airship config
|
||||
|
@ -17,10 +17,7 @@ airshipctl config set-context NAME [flags]
|
||||
|
||||
# Create a new context named "exampleContext"
|
||||
airshipctl config set-context exampleContext \
|
||||
--namespace=kube-system \
|
||||
--manifest=exampleManifest \
|
||||
--user=exampleUser
|
||||
--cluster-type=target
|
||||
--encryption-config=exampleEncryptionConfig
|
||||
|
||||
# Update the manifest of the current-context
|
||||
@ -33,14 +30,11 @@ airshipctl config set-context \
|
||||
### Options
|
||||
|
||||
```
|
||||
--cluster string set the cluster for the specified context
|
||||
--cluster-type string set the cluster-type for the specified context
|
||||
--current update the current context
|
||||
--encryption-config string set the encryption config for the specified context
|
||||
-h, --help help for set-context
|
||||
--manifest string set the manifest for the specified context
|
||||
--namespace string set the namespace for the specified context
|
||||
--user string set the user for the specified context
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -66,6 +66,7 @@ func NewCommand(cfgFactory config.Factory) (*Command, error) {
|
||||
|
||||
// Init runs clusterctl init
|
||||
func (c *Command) Init() error {
|
||||
log.Printf("config %s \n context %s", c.kubeconfigPath, c.kubeconfigContext)
|
||||
return c.client.Init(c.kubeconfigPath, c.kubeconfigContext)
|
||||
}
|
||||
|
||||
|
22
pkg/clusterctl/cmd/testdata/airshipconfig.yaml
vendored
22
pkg/clusterctl/cmd/testdata/airshipconfig.yaml
vendored
@ -1,25 +1,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
dummy_bootstrap_config:
|
||||
container:
|
||||
volume: /tmp/airship:/config
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
containerRuntime: docker
|
||||
builder:
|
||||
userDataFileName: user-data
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
remoteDirect:
|
||||
isoUrl: http://localhost:8099/ubuntu-focal.iso
|
||||
clusters:
|
||||
dummycluster:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
bootstrapInfo: dummy_bootstrap_config
|
||||
clusterKubeconf: dummycluster_ephemeral
|
||||
contexts:
|
||||
dummy_cluster:
|
||||
contextKubeconf: dummy_cluster
|
||||
contextKubeconf: dummycluster_ephemeral
|
||||
manifest: dummy_manifest
|
||||
currentContext: dummy_cluster
|
||||
kind: Config
|
||||
@ -39,5 +21,3 @@ manifests:
|
||||
url: http://dummy.url.com/primary.git
|
||||
subPath: site
|
||||
targetPath: testdata
|
||||
users:
|
||||
dummy_user: {}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// AuthInfo contains kubeConfig AuthInfo Object
|
||||
type AuthInfo struct {
|
||||
// KubeConfig AuthInfo Object
|
||||
authInfo *api.AuthInfo
|
||||
}
|
||||
|
||||
// AuthInfo functions
|
||||
func (c *AuthInfo) String() string {
|
||||
kauthinfo := c.KubeAuthInfo()
|
||||
kyaml, err := yaml.Marshal(&kauthinfo)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(kyaml)
|
||||
}
|
||||
|
||||
// KubeAuthInfo returns kubeConfig AuthInfo Object
|
||||
func (c *AuthInfo) KubeAuthInfo() *api.AuthInfo {
|
||||
return c.authInfo
|
||||
}
|
||||
|
||||
// SetKubeAuthInfo sets kubeConfig in AuthInfo
|
||||
func (c *AuthInfo) SetKubeAuthInfo(kc *api.AuthInfo) {
|
||||
c.authInfo = kc
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
func TestGetAuthInfos(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
authinfos, err := conf.GetAuthInfos()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, authinfos, 3)
|
||||
}
|
||||
|
||||
func TestGetAuthInfo(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
authinfo, err := conf.GetAuthInfo("def-user")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test Positives
|
||||
assert.EqualValues(t, authinfo.KubeAuthInfo().Username, "dummy_username")
|
||||
|
||||
// Test Wrong Cluster
|
||||
_, err = conf.GetAuthInfo("unknown")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAddAuthInfo(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
co := testutil.DummyAuthInfoOptions()
|
||||
authinfo := conf.AddAuthInfo(co)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name], authinfo)
|
||||
}
|
||||
|
||||
func TestModifyAuthInfo(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
co := testutil.DummyAuthInfoOptions()
|
||||
authinfo := conf.AddAuthInfo(co)
|
||||
|
||||
co.Username += stringDelta
|
||||
co.Password = newPassword
|
||||
co.ClientCertificate = newCertificate
|
||||
co.ClientKey = newKey
|
||||
co.Token = newToken
|
||||
conf.ModifyAuthInfo(authinfo, co)
|
||||
modifiedAuthinfo, err := conf.GetAuthInfo(co.Name)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Username, co.Username)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Password, co.Password)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().ClientCertificate, co.ClientCertificate)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().ClientKey, co.ClientKey)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Token, co.Token)
|
||||
assert.EqualValues(t, modifiedAuthinfo, authinfo)
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Cluster contains information about how to communicate with a kubernetes cluster
|
||||
type Cluster struct {
|
||||
// Complex cluster name defined by the using <cluster name>_<cluster type>)
|
||||
NameInKubeconf string `json:"clusterKubeconf"`
|
||||
|
||||
// KubeConfig Cluster Object
|
||||
cluster *api.Cluster
|
||||
|
||||
// Management configuration which will be used for all hosts in the cluster
|
||||
ManagementConfiguration string `json:"managementConfiguration"`
|
||||
}
|
||||
|
||||
// ClusterPurpose encapsulates the Cluster Type as an enumeration
|
||||
type ClusterPurpose struct {
|
||||
// Cluster map of referenceable names to cluster configs
|
||||
ClusterTypes map[string]*Cluster `json:"clusterType"`
|
||||
}
|
||||
|
||||
// ClusterComplexName holds the complex cluster name information
|
||||
// Encapsulates the different operations around using it.
|
||||
type ClusterComplexName struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (c *Cluster) String() string {
|
||||
cyaml, err := yaml.Marshal(&c)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
kcluster := c.KubeCluster()
|
||||
kyaml, err := yaml.Marshal(&kcluster)
|
||||
if err != nil {
|
||||
return string(cyaml)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s\n%s", string(cyaml), string(kyaml))
|
||||
}
|
||||
|
||||
// PrettyString returns cluster information in a formatted string
|
||||
func (c *Cluster) PrettyString() string {
|
||||
clusterName := NewClusterComplexNameFromKubeClusterName(c.NameInKubeconf)
|
||||
return fmt.Sprintf("Cluster: %s\n%s:\n%s", clusterName.Name, clusterName.Type, c)
|
||||
}
|
||||
|
||||
// KubeCluster returns KubeConfig Cluster Object
|
||||
func (c *Cluster) KubeCluster() *api.Cluster {
|
||||
return c.cluster
|
||||
}
|
||||
|
||||
// SetKubeCluster sets cluster in KubeConfig
|
||||
func (c *Cluster) SetKubeCluster(kc *api.Cluster) {
|
||||
c.cluster = kc
|
||||
}
|
||||
|
||||
// String returns cluster's complex name, formed by combining name and type with a delimiter('_')
|
||||
func (c *ClusterComplexName) String() string {
|
||||
return strings.Join([]string{c.Name, c.Type}, AirshipClusterNameSeparator)
|
||||
}
|
||||
|
||||
// ValidClusterType checks for the possible options for cluster type
|
||||
// Returns error when invalid cluster type is given
|
||||
func ValidClusterType(clusterType string) error {
|
||||
for _, validType := range AllClusterTypes {
|
||||
if clusterType == validType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("cluster type must be one of %v", AllClusterTypes)
|
||||
}
|
||||
|
||||
// NewClusterPurpose is a convenience function that returns a new ClusterPurpose
|
||||
func NewClusterPurpose() *ClusterPurpose {
|
||||
return &ClusterPurpose{
|
||||
ClusterTypes: make(map[string]*Cluster),
|
||||
}
|
||||
}
|
||||
|
||||
// NewClusterComplexName returns a ClusterComplexName with the given name and type.
|
||||
func NewClusterComplexName(clusterName, clusterType string) ClusterComplexName {
|
||||
return ClusterComplexName{
|
||||
Name: clusterName,
|
||||
Type: clusterType,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClusterComplexNameFromKubeClusterName takes the name of a cluster in a
|
||||
// format which might be found in a kubeconfig file. This may be a simple
|
||||
// string (e.g. myCluster), or it may be prepended with the type of the cluster
|
||||
// (e.g. myCluster_target)
|
||||
//
|
||||
// If a valid cluster type was appended, the returned ClusterComplexName will
|
||||
// have that type. If no cluster type is provided, the
|
||||
// AirshipDefaultClusterType will be used.
|
||||
func NewClusterComplexNameFromKubeClusterName(kubeClusterName string) ClusterComplexName {
|
||||
parts := strings.Split(kubeClusterName, AirshipClusterNameSeparator)
|
||||
|
||||
if len(parts) == 1 {
|
||||
return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType)
|
||||
}
|
||||
|
||||
// kubeClusterName matches the format myCluster_something.
|
||||
// Let's check if "something" is a clusterType.
|
||||
potentialType := parts[len(parts)-1]
|
||||
for _, ct := range AllClusterTypes {
|
||||
if potentialType == ct {
|
||||
// Rejoin the parts in the case of "my_cluster_etc_etc_<clusterType>"
|
||||
name := strings.Join(parts[:len(parts)-1], AirshipClusterNameSeparator)
|
||||
return NewClusterComplexName(name, potentialType)
|
||||
}
|
||||
}
|
||||
|
||||
// "something" is not a valid clusterType, so just use the default
|
||||
return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType)
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
func TestPrettyString(t *testing.T) {
|
||||
fSys := testutil.SetupTestFs(t, "testdata")
|
||||
data, err := fSys.ReadFile("/prettycluster-string.yaml")
|
||||
require.NoError(t, err)
|
||||
|
||||
cluster := testutil.DummyCluster()
|
||||
assert.EqualValues(t, cluster.PrettyString(), string(data))
|
||||
}
|
||||
|
||||
func TestValidClusterTypeFail(t *testing.T) {
|
||||
err := config.ValidClusterType("Fake")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGetCluster(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
cluster, err := conf.GetCluster("def", config.Ephemeral)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test Positives
|
||||
assert.EqualValues(t, cluster.NameInKubeconf, "def_ephemeral")
|
||||
assert.EqualValues(t, cluster.KubeCluster().Server, "http://5.6.7.8")
|
||||
|
||||
// Test Wrong Cluster
|
||||
_, err = conf.GetCluster("unknown", config.Ephemeral)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test Wrong Cluster Type
|
||||
_, err = conf.GetCluster("def", "Unknown")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAddCluster(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
co := testutil.DummyClusterOptions()
|
||||
cluster, err := conf.AddCluster(co)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, conf.Clusters[co.Name].ClusterTypes[co.ClusterType], cluster)
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
/*
|
||||
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
|
||||
@ -47,12 +45,6 @@ type Config struct {
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
|
||||
// Clusters is a map of referenceable names to cluster configs
|
||||
Clusters map[string]*ClusterPurpose `json:"clusters"`
|
||||
|
||||
// AuthInfos is a map of referenceable names to user configs
|
||||
AuthInfos map[string]*AuthInfo `json:"users"`
|
||||
|
||||
// Permissions is a struct of permissions for file and directory
|
||||
Permissions Permissions `json:"permissions,omitempty"`
|
||||
|
||||
@ -124,9 +116,6 @@ func CreateConfig(airshipConfigPath string, kubeConfigPath string) error {
|
||||
cfg := NewConfig()
|
||||
cfg.kubeConfig = NewKubeConfig()
|
||||
cfg.initConfigPath(airshipConfigPath, kubeConfigPath)
|
||||
if err := cfg.reconcileConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
return cfg.PersistConfig(true)
|
||||
}
|
||||
|
||||
@ -170,8 +159,7 @@ func (c *Config) LoadConfig(airshipConfigPath, kubeConfigPath string, create boo
|
||||
return err
|
||||
}
|
||||
|
||||
// Lets navigate through the kubeconfig to populate the references in airship config
|
||||
return c.reconcileConfig()
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadFromAirConfig populates the Config from the file found at airshipConfigPath.
|
||||
@ -217,220 +205,14 @@ func (c *Config) loadKubeConfig(kubeConfigPath string, create bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// reconcileConfig serves two functions:
|
||||
// 1 - it will consume from kubeconfig and update airship config
|
||||
// For cluster that do not comply with the airship cluster type expectations a default
|
||||
// behavior will be implemented. Such as ,by default they will be tar or ephemeral
|
||||
// 2 - it will update kubeconfig cluster objects with the appropriate <clustername>_<clustertype> convention
|
||||
func (c *Config) reconcileConfig() error {
|
||||
updatedClusterNames, persistIt := c.reconcileClusters()
|
||||
c.reconcileContexts(updatedClusterNames)
|
||||
c.reconcileAuthInfos()
|
||||
c.reconcileCurrentContext()
|
||||
|
||||
// I changed things during the reconciliation
|
||||
// Lets reflect them in the config files
|
||||
// Specially useful if the config is loaded during a get operation
|
||||
// If it was a Set this would have happened eventually any way
|
||||
if persistIt {
|
||||
return c.PersistConfig(true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// reconcileClusters synchronizes the airshipconfig file with the kubeconfig file.
|
||||
//
|
||||
// It iterates over the clusters listed in the kubeconfig. If any cluster in
|
||||
// the kubeconfig does not meet the <name>_<type> convention, the name is
|
||||
// first changed to the airship default.
|
||||
//
|
||||
// It then updates the airshipconfig's names of those clusters, as well as the
|
||||
// pointer to the clusters.
|
||||
// If the cluster wasn't referenced prior to the call, it is created; otherwise
|
||||
// it is modified.
|
||||
//
|
||||
// Finally, any clusters listed in the airshipconfig that are no longer
|
||||
// referenced in the kubeconfig are deleted
|
||||
//
|
||||
// The function returns a mapping of changed names in the kubeconfig, as well
|
||||
// as a boolean denoting that the config files need to be written to file
|
||||
func (c *Config) reconcileClusters() (map[string]string, bool) {
|
||||
// updatedClusterNames is a mapping from OLD cluster names to NEW
|
||||
// cluster names. This will be used later when we update contexts
|
||||
updatedClusterNames := map[string]string{}
|
||||
|
||||
persistIt := false
|
||||
for clusterName, cluster := range c.kubeConfig.Clusters {
|
||||
clusterComplexName := NewClusterComplexNameFromKubeClusterName(clusterName)
|
||||
// Check if the cluster from the kubeconfig file complies with
|
||||
// the airship naming convention
|
||||
if clusterName != clusterComplexName.String() {
|
||||
// Update the kubeconfig with proper airship name
|
||||
c.kubeConfig.Clusters[clusterComplexName.String()] = cluster
|
||||
delete(c.kubeConfig.Clusters, clusterName)
|
||||
|
||||
// We also need to save the mapping from the old name
|
||||
// so we can update the context in the kubeconfig later
|
||||
updatedClusterNames[clusterName] = clusterComplexName.String()
|
||||
|
||||
// Since we've modified the kubeconfig object, we'll
|
||||
// need to let the caller know that the kubeconfig file
|
||||
// needs to be updated
|
||||
persistIt = true
|
||||
|
||||
// Otherwise this is a cluster that didnt have an
|
||||
// airship cluster type, however when you added the
|
||||
// cluster type
|
||||
// Probable should just add a number _<COUNTER to it
|
||||
}
|
||||
|
||||
// The cluster in the kubeconfig is not present in the airship config. Create it.
|
||||
if c.Clusters[clusterComplexName.Name] == nil {
|
||||
c.Clusters[clusterComplexName.Name] = NewClusterPurpose()
|
||||
}
|
||||
|
||||
// NOTE(drewwalters96): This is a user error because a cluster is defined in name but incomplete. We
|
||||
// need to fail sooner than this function; add up-front validation for this later.
|
||||
if c.Clusters[clusterComplexName.Name].ClusterTypes == nil {
|
||||
c.Clusters[clusterComplexName.Name].ClusterTypes = make(map[string]*Cluster)
|
||||
}
|
||||
|
||||
// The cluster is defined, but the type is not. Define the type.
|
||||
if c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] == nil {
|
||||
c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] = NewCluster()
|
||||
}
|
||||
|
||||
// Point cluster at kubeconfig
|
||||
configCluster := c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type]
|
||||
configCluster.NameInKubeconf = clusterComplexName.String()
|
||||
|
||||
// Store the reference to the KubeConfig Cluster in the Airship Config
|
||||
configCluster.SetKubeCluster(cluster)
|
||||
}
|
||||
|
||||
persistIt = c.rmConfigClusterStragglers(persistIt)
|
||||
|
||||
return updatedClusterNames, persistIt
|
||||
}
|
||||
|
||||
// Removes Cluster configuration that exist in Airship Config and do not have
|
||||
// any kubeconfig appropriate <clustername>_<clustertype> entries
|
||||
func (c *Config) rmConfigClusterStragglers(persistIt bool) bool {
|
||||
rccs := persistIt
|
||||
// Checking if there is any Cluster reference in airship config that does not match
|
||||
// an actual Cluster struct in kubeconfig
|
||||
for clusterName := range c.Clusters {
|
||||
for cType, cluster := range c.Clusters[clusterName].ClusterTypes {
|
||||
if _, found := c.kubeConfig.Clusters[cluster.NameInKubeconf]; !found {
|
||||
// Instead of removing it , I could add a empty entry in kubeconfig as well
|
||||
// Will see what is more appropriate with use of Modules configuration
|
||||
delete(c.Clusters[clusterName].ClusterTypes, cType)
|
||||
|
||||
// If that was the last cluster type, then we
|
||||
// should delete the cluster entry
|
||||
if len(c.Clusters[clusterName].ClusterTypes) == 0 {
|
||||
delete(c.Clusters, clusterName)
|
||||
}
|
||||
rccs = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return rccs
|
||||
}
|
||||
|
||||
func (c *Config) reconcileContexts(updatedClusterNames map[string]string) {
|
||||
for key, context := range c.kubeConfig.Contexts {
|
||||
// Check if the Cluster name referred to by the context
|
||||
// was updated during the cluster reconcile
|
||||
if newName, ok := updatedClusterNames[context.Cluster]; ok {
|
||||
context.Cluster = newName
|
||||
}
|
||||
|
||||
if c.Contexts[key] == nil {
|
||||
c.Contexts[key] = NewContext()
|
||||
}
|
||||
// Make sure the name matches
|
||||
c.Contexts[key].NameInKubeconf = context.Cluster
|
||||
c.Contexts[key].SetKubeContext(context)
|
||||
|
||||
// What about if a Context refers to a cluster that does not
|
||||
// exist in airship config
|
||||
clusterName := NewClusterComplexNameFromKubeClusterName(context.Cluster)
|
||||
if c.Clusters[clusterName.Name] == nil {
|
||||
// I cannot create this cluster, it will have empty information
|
||||
// Best course of action is to delete it I think
|
||||
delete(c.kubeConfig.Contexts, key)
|
||||
}
|
||||
}
|
||||
// Checking if there is any Context reference in airship config that does not match
|
||||
// an actual Context struct in kubeconfig, if they do not exists I will delete
|
||||
// Since context in airship config are only references mainly.
|
||||
for key := range c.Contexts {
|
||||
if c.kubeConfig.Contexts[key] == nil {
|
||||
delete(c.Contexts, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) reconcileAuthInfos() {
|
||||
for key, authinfo := range c.kubeConfig.AuthInfos {
|
||||
// Simple check if the AuthInfo name is referenced in airship config
|
||||
if c.AuthInfos[key] == nil && authinfo != nil {
|
||||
// Add the reference
|
||||
c.AuthInfos[key] = NewAuthInfo()
|
||||
}
|
||||
c.AuthInfos[key].authInfo = authinfo
|
||||
}
|
||||
// Checking if there is any AuthInfo reference in airship config that does not match
|
||||
// an actual Auth Info struct in kubeconfig
|
||||
for key := range c.AuthInfos {
|
||||
if c.kubeConfig.AuthInfos[key] == nil {
|
||||
delete(c.AuthInfos, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) reconcileCurrentContext() {
|
||||
// If the Airship current context is different that the current context in the kubeconfig
|
||||
// then
|
||||
// - if the airship current context is valid, then updated kubeconfig CC
|
||||
// - if the airship currentcontext is invalid, and the kubeconfig CC is valid, then create the reference
|
||||
// - otherwise , they are both empty. Make sure
|
||||
|
||||
if c.Contexts[c.CurrentContext] == nil { // Its not valid
|
||||
if c.Contexts[c.kubeConfig.CurrentContext] != nil {
|
||||
c.CurrentContext = c.kubeConfig.CurrentContext
|
||||
}
|
||||
} else {
|
||||
// Overpowers kubeConfig CurrentContext
|
||||
if c.kubeConfig.CurrentContext != c.CurrentContext {
|
||||
c.kubeConfig.CurrentContext = c.CurrentContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureComplete verifies that a Config object is ready to use.
|
||||
// A complete Config object meets the following criteria:
|
||||
// * At least 1 Cluster is defined
|
||||
// * At least 1 AuthInfo (user) is defined
|
||||
// * At least 1 Context is defined
|
||||
// * At least 1 Manifest is defined
|
||||
// * The CurrentContext is set
|
||||
// * The CurrentContext identifies an existing Context
|
||||
// * The CurrentContext identifies an existing Manifest
|
||||
func (c *Config) EnsureComplete() error {
|
||||
if len(c.Clusters) == 0 {
|
||||
return ErrMissingConfig{
|
||||
What: "At least one cluster needs to be defined",
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.AuthInfos) == 0 {
|
||||
return ErrMissingConfig{
|
||||
What: "At least one Authentication Information (User) needs to be defined",
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Contexts) == 0 {
|
||||
return ErrMissingConfig{
|
||||
What: "At least one Context needs to be defined",
|
||||
@ -560,113 +342,6 @@ func (c *Config) SetKubeConfig(kubeConfig *clientcmdapi.Config) {
|
||||
c.kubeConfig = kubeConfig
|
||||
}
|
||||
|
||||
// GetCluster returns a cluster instance
|
||||
func (c *Config) GetCluster(cName, cType string) (*Cluster, error) {
|
||||
_, exists := c.Clusters[cName]
|
||||
if !exists {
|
||||
return nil, ErrMissingConfig{What: fmt.Sprintf("Cluster with name '%s' of type '%s'", cName, cType)}
|
||||
}
|
||||
// Alternative to this would be enhance Cluster.String() to embed the appropriate kubeconfig cluster information
|
||||
cluster, exists := c.Clusters[cName].ClusterTypes[cType]
|
||||
if !exists {
|
||||
return nil, ErrMissingConfig{What: fmt.Sprintf("Cluster with name '%s' of type '%s'", cName, cType)}
|
||||
}
|
||||
return cluster, nil
|
||||
}
|
||||
|
||||
// AddCluster creates a new cluster and returns the
|
||||
// newly created cluster object
|
||||
func (c *Config) AddCluster(theCluster *ClusterOptions) (*Cluster, error) {
|
||||
// Need to create new cluster placeholder
|
||||
// Get list of ClusterPurposes that match the theCluster.name
|
||||
// Cluster might exists, but ClusterPurpose should not
|
||||
_, exists := c.Clusters[theCluster.Name]
|
||||
if !exists {
|
||||
c.Clusters[theCluster.Name] = NewClusterPurpose()
|
||||
}
|
||||
// Create the new Airship config Cluster
|
||||
nCluster := NewCluster()
|
||||
c.Clusters[theCluster.Name].ClusterTypes[theCluster.ClusterType] = nCluster
|
||||
// Create a new KubeConfig Cluster object as well
|
||||
kcluster := clientcmdapi.NewCluster()
|
||||
clusterName := NewClusterComplexName(theCluster.Name, theCluster.ClusterType)
|
||||
nCluster.NameInKubeconf = clusterName.String()
|
||||
nCluster.SetKubeCluster(kcluster)
|
||||
|
||||
c.KubeConfig().Clusters[clusterName.String()] = kcluster
|
||||
|
||||
// Ok , I have initialized structs for the Cluster information
|
||||
// We can use Modify to populate the correct information
|
||||
return c.ModifyCluster(nCluster, theCluster)
|
||||
}
|
||||
|
||||
// ModifyCluster updates cluster object with given cluster options
|
||||
func (c *Config) ModifyCluster(cluster *Cluster, theCluster *ClusterOptions) (*Cluster, error) {
|
||||
kcluster := cluster.KubeCluster()
|
||||
if kcluster == nil {
|
||||
return cluster, nil
|
||||
}
|
||||
if theCluster.Server != "" {
|
||||
kcluster.Server = theCluster.Server
|
||||
}
|
||||
if theCluster.InsecureSkipTLSVerify {
|
||||
kcluster.InsecureSkipTLSVerify = theCluster.InsecureSkipTLSVerify
|
||||
// Specifying insecur mode clears any certificate authority
|
||||
if kcluster.InsecureSkipTLSVerify {
|
||||
kcluster.CertificateAuthority = ""
|
||||
kcluster.CertificateAuthorityData = nil
|
||||
}
|
||||
}
|
||||
if theCluster.CertificateAuthority == "" {
|
||||
return cluster, nil
|
||||
}
|
||||
|
||||
if theCluster.EmbedCAData {
|
||||
readData, err := ioutil.ReadFile(theCluster.CertificateAuthority)
|
||||
kcluster.CertificateAuthorityData = readData
|
||||
if err != nil {
|
||||
return cluster, err
|
||||
}
|
||||
kcluster.InsecureSkipTLSVerify = false
|
||||
kcluster.CertificateAuthority = ""
|
||||
} else {
|
||||
caPath, err := filepath.Abs(theCluster.CertificateAuthority)
|
||||
if err != nil {
|
||||
return cluster, err
|
||||
}
|
||||
kcluster.CertificateAuthority = caPath
|
||||
// Specifying a certificate authority file clears certificate authority data and insecure mode
|
||||
if caPath != "" {
|
||||
kcluster.InsecureSkipTLSVerify = false
|
||||
kcluster.CertificateAuthorityData = nil
|
||||
}
|
||||
}
|
||||
return cluster, nil
|
||||
}
|
||||
|
||||
// GetClusters returns all of the clusters associated with the Config sorted by name
|
||||
func (c *Config) GetClusters() []*Cluster {
|
||||
keys := make([]string, 0, len(c.Clusters))
|
||||
for name := range c.Clusters {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
clusters := make([]*Cluster, 0, len(c.Clusters))
|
||||
for _, name := range keys {
|
||||
for _, clusterType := range AllClusterTypes {
|
||||
cluster, exists := c.Clusters[name].ClusterTypes[clusterType]
|
||||
if exists {
|
||||
// If it doesn't exist, then there must not be
|
||||
// a cluster with this name/type combination.
|
||||
// This is expected behavior
|
||||
clusters = append(clusters, cluster)
|
||||
}
|
||||
}
|
||||
}
|
||||
return clusters
|
||||
}
|
||||
|
||||
// GetContext returns a context instance
|
||||
func (c *Config) GetContext(cName string) (*Context, error) {
|
||||
context, exists := c.Contexts[cName]
|
||||
@ -707,30 +382,19 @@ 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
|
||||
context := clientcmdapi.NewContext()
|
||||
nContext.NameInKubeconf = theContext.Name
|
||||
|
||||
nContext.SetKubeContext(context)
|
||||
c.KubeConfig().Contexts[theContext.Name] = context
|
||||
|
||||
// Ok , I have initialized structs for the Context information
|
||||
// We can use Modify to populate the correct information
|
||||
c.ModifyContext(nContext, theContext)
|
||||
nContext.ClusterType()
|
||||
return nContext
|
||||
}
|
||||
|
||||
// ModifyContext updates Context object with given given context options
|
||||
func (c *Config) ModifyContext(context *Context, theContext *ContextOptions) {
|
||||
kubeContext := context.KubeContext()
|
||||
if kubeContext == nil {
|
||||
return
|
||||
}
|
||||
if theContext.Cluster != "" {
|
||||
kubeContext.Cluster = theContext.Cluster
|
||||
}
|
||||
if theContext.AuthInfo != "" {
|
||||
kubeContext.AuthInfo = theContext.AuthInfo
|
||||
if theContext.ManagementConfiguration != "" {
|
||||
context.ManagementConfiguration = theContext.ManagementConfiguration
|
||||
}
|
||||
if theContext.Manifest != "" {
|
||||
context.Manifest = theContext.Manifest
|
||||
@ -738,16 +402,11 @@ func (c *Config) ModifyContext(context *Context, theContext *ContextOptions) {
|
||||
if theContext.EncryptionConfig != "" {
|
||||
context.EncryptionConfig = theContext.EncryptionConfig
|
||||
}
|
||||
if theContext.Namespace != "" {
|
||||
kubeContext.Namespace = theContext.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentContext 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) {
|
||||
@ -759,27 +418,6 @@ func (c *Config) GetCurrentContext() (*Context, error) {
|
||||
return currentContext, nil
|
||||
}
|
||||
|
||||
// CurrentContextCluster returns the Cluster for the current context
|
||||
func (c *Config) CurrentContextCluster() (*Cluster, error) {
|
||||
currentContext, err := c.GetCurrentContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clusterName := NewClusterComplexNameFromKubeClusterName(currentContext.KubeContext().Cluster)
|
||||
|
||||
return c.Clusters[clusterName.Name].ClusterTypes[currentContext.ClusterType()], nil
|
||||
}
|
||||
|
||||
// CurrentContextAuthInfo returns the AuthInfo for the current context
|
||||
func (c *Config) CurrentContextAuthInfo() (*AuthInfo, error) {
|
||||
currentContext, err := c.GetCurrentContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.AuthInfos[currentContext.KubeContext().AuthInfo], nil
|
||||
}
|
||||
|
||||
// CurrentContextManifest returns the manifest for the current context
|
||||
func (c *Config) CurrentContextManifest() (*Manifest, error) {
|
||||
currentContext, err := c.GetCurrentContext()
|
||||
@ -798,10 +436,6 @@ func (c *Config) CurrentContextEntryPoint(phase string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = ValidClusterType(clusterType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ccm, err := c.CurrentContextManifest()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -844,167 +478,6 @@ func (c *Config) CurrentContextClusterName() (string, error) {
|
||||
return context.ClusterName(), nil
|
||||
}
|
||||
|
||||
// GetAuthInfo returns an instance of authino
|
||||
// Credential or AuthInfo related methods
|
||||
func (c *Config) GetAuthInfo(aiName string) (*AuthInfo, error) {
|
||||
authinfo, exists := c.AuthInfos[aiName]
|
||||
if !exists {
|
||||
return nil, ErrMissingConfig{What: fmt.Sprintf("User credentials with name '%s'", aiName)}
|
||||
}
|
||||
decodedAuthInfo, err := DecodeAuthInfo(authinfo.authInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authinfo.authInfo = decodedAuthInfo
|
||||
return authinfo, nil
|
||||
}
|
||||
|
||||
// GetAuthInfos returns a slice containing all the AuthInfos associated with
|
||||
// the Config sorted by name
|
||||
func (c *Config) GetAuthInfos() ([]*AuthInfo, error) {
|
||||
keys := make([]string, 0, len(c.AuthInfos))
|
||||
for name := range c.AuthInfos {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
authInfos := make([]*AuthInfo, 0, len(c.AuthInfos))
|
||||
for _, name := range keys {
|
||||
decodedAuthInfo, err := DecodeAuthInfo(c.AuthInfos[name].authInfo)
|
||||
if err != nil {
|
||||
return []*AuthInfo{}, err
|
||||
}
|
||||
c.AuthInfos[name].authInfo = decodedAuthInfo
|
||||
authInfos = append(authInfos, c.AuthInfos[name])
|
||||
}
|
||||
return authInfos, nil
|
||||
}
|
||||
|
||||
// AddAuthInfo creates new AuthInfo with context details updated
|
||||
// in the airship config and kube config
|
||||
func (c *Config) AddAuthInfo(theAuthInfo *AuthInfoOptions) *AuthInfo {
|
||||
// Create the new Airship config context
|
||||
nAuthInfo := NewAuthInfo()
|
||||
c.AuthInfos[theAuthInfo.Name] = nAuthInfo
|
||||
// Create a new KubeConfig AuthInfo object as well
|
||||
authInfo := clientcmdapi.NewAuthInfo()
|
||||
nAuthInfo.authInfo = authInfo
|
||||
c.KubeConfig().AuthInfos[theAuthInfo.Name] = authInfo
|
||||
|
||||
c.ModifyAuthInfo(nAuthInfo, theAuthInfo)
|
||||
return nAuthInfo
|
||||
}
|
||||
|
||||
// ModifyAuthInfo updates the AuthInfo in the Config object
|
||||
func (c *Config) ModifyAuthInfo(authinfo *AuthInfo, theAuthInfo *AuthInfoOptions) {
|
||||
kubeAuthInfo := EncodeAuthInfo(authinfo.KubeAuthInfo())
|
||||
if kubeAuthInfo == nil {
|
||||
return
|
||||
}
|
||||
if theAuthInfo.ClientCertificate != "" {
|
||||
kubeAuthInfo.ClientCertificate = EncodeString(theAuthInfo.ClientCertificate)
|
||||
}
|
||||
if theAuthInfo.Token != "" {
|
||||
kubeAuthInfo.Token = EncodeString(theAuthInfo.Token)
|
||||
}
|
||||
if theAuthInfo.Username != "" {
|
||||
kubeAuthInfo.Username = theAuthInfo.Username
|
||||
}
|
||||
if theAuthInfo.Password != "" {
|
||||
kubeAuthInfo.Password = EncodeString(theAuthInfo.Password)
|
||||
}
|
||||
if theAuthInfo.ClientKey != "" {
|
||||
kubeAuthInfo.ClientKey = EncodeString(theAuthInfo.ClientKey)
|
||||
}
|
||||
}
|
||||
|
||||
// ImportFromKubeConfig absorbs the clusters, contexts and credentials from the
|
||||
// given kubeConfig
|
||||
func (c *Config) ImportFromKubeConfig(kubeConfigPath string) error {
|
||||
_, err := os.Stat(kubeConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kubeConfig, err := clientcmd.LoadFromFile(kubeConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.importClusters(kubeConfig)
|
||||
c.importContexts(kubeConfig)
|
||||
c.importAuthInfos(kubeConfig)
|
||||
return c.PersistConfig(true)
|
||||
}
|
||||
|
||||
func (c *Config) importClusters(importKubeConfig *clientcmdapi.Config) {
|
||||
for clusterName, cluster := range importKubeConfig.Clusters {
|
||||
clusterComplexName := NewClusterComplexNameFromKubeClusterName(clusterName)
|
||||
if _, err := c.GetCluster(clusterComplexName.Name, clusterComplexName.Type); err == nil {
|
||||
// err == nil implies that we were successfully able to
|
||||
// get the cluster from the existing configuration.
|
||||
// Since existing clusters takes precedence, skip this cluster
|
||||
continue
|
||||
}
|
||||
|
||||
// Initialize the new cluster for the airship configuration
|
||||
airshipCluster := NewCluster()
|
||||
airshipCluster.NameInKubeconf = clusterComplexName.String()
|
||||
// Store the reference to the KubeConfig Cluster in the Airship Config
|
||||
airshipCluster.SetKubeCluster(cluster)
|
||||
|
||||
// Update the airship configuration
|
||||
if _, ok := c.Clusters[clusterComplexName.Name]; !ok {
|
||||
c.Clusters[clusterComplexName.Name] = NewClusterPurpose()
|
||||
}
|
||||
c.Clusters[clusterComplexName.Name].ClusterTypes[clusterComplexName.Type] = airshipCluster
|
||||
c.kubeConfig.Clusters[clusterComplexName.String()] = cluster
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) importContexts(importKubeConfig *clientcmdapi.Config) {
|
||||
// TODO(howell): This function doesn't handle the case when an incoming
|
||||
// context refers to a cluster that doesn't exist in the airship
|
||||
// configuration.
|
||||
for kubeContextName, kubeContext := range importKubeConfig.Contexts {
|
||||
if _, ok := c.kubeConfig.Contexts[kubeContextName]; ok {
|
||||
// Since existing contexts take precedence, skip this context
|
||||
continue
|
||||
}
|
||||
|
||||
clusterComplexName := NewClusterComplexNameFromKubeClusterName(kubeContext.Cluster)
|
||||
if kubeContext.Cluster != clusterComplexName.String() {
|
||||
// If the name of cluster from the kubeConfig doesn't
|
||||
// match the clusterComplexName, it needs to be updated
|
||||
kubeContext.Cluster = clusterComplexName.String()
|
||||
}
|
||||
|
||||
airshipContext, ok := c.Contexts[kubeContextName]
|
||||
if !ok {
|
||||
airshipContext = NewContext()
|
||||
}
|
||||
airshipContext.NameInKubeconf = kubeContext.Cluster
|
||||
airshipContext.Manifest = AirshipDefaultManifest
|
||||
airshipContext.SetKubeContext(kubeContext)
|
||||
|
||||
// Store the contexts in the airship configuration
|
||||
c.Contexts[kubeContextName] = airshipContext
|
||||
c.kubeConfig.Contexts[kubeContextName] = kubeContext
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) importAuthInfos(importKubeConfig *clientcmdapi.Config) {
|
||||
for key, authinfo := range importKubeConfig.AuthInfos {
|
||||
if _, ok := c.AuthInfos[key]; ok {
|
||||
// Since existing credentials take precedence, skip this credential
|
||||
continue
|
||||
}
|
||||
|
||||
c.AuthInfos[key] = NewAuthInfo()
|
||||
c.AuthInfos[key].SetKubeAuthInfo(authinfo)
|
||||
c.kubeConfig.AuthInfos[key] = authinfo
|
||||
}
|
||||
}
|
||||
|
||||
// GetManifests returns all of the Manifests associated with the Config sorted by name
|
||||
func (c *Config) GetManifests() []*Manifest {
|
||||
keys := make([]string, 0, len(c.Manifests))
|
||||
@ -1164,20 +637,20 @@ func (c *Config) ModifyEncryptionConfig(encryptionConfig *EncryptionConfig, opti
|
||||
|
||||
// CurrentContextManagementConfig returns the management options for the current context
|
||||
func (c *Config) CurrentContextManagementConfig() (*ManagementConfiguration, error) {
|
||||
currentCluster, err := c.CurrentContextCluster()
|
||||
currentContext, err := c.GetCurrentContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if currentCluster.ManagementConfiguration == "" {
|
||||
if currentContext.ManagementConfiguration == "" {
|
||||
return nil, ErrMissingConfig{
|
||||
What: fmt.Sprintf("No management config listed for cluster %s", currentCluster.NameInKubeconf),
|
||||
What: fmt.Sprintf("No management config listed for cluster %s", currentContext.NameInKubeconf),
|
||||
}
|
||||
}
|
||||
|
||||
managementCfg, exists := c.ManagementConfiguration[currentCluster.ManagementConfiguration]
|
||||
managementCfg, exists := c.ManagementConfiguration[currentContext.ManagementConfiguration]
|
||||
if !exists {
|
||||
return nil, ErrMissingManagementConfiguration{cluster: currentCluster}
|
||||
return nil, ErrMissingManagementConfiguration{context: currentContext}
|
||||
}
|
||||
|
||||
return managementCfg, nil
|
||||
@ -1205,44 +678,3 @@ func (c *Config) CurrentContextManifestMetadata() (*Metadata, error) {
|
||||
}
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
// DecodeAuthInfo returns authInfo with credentials decoded
|
||||
func DecodeAuthInfo(authinfo *clientcmdapi.AuthInfo) (*clientcmdapi.AuthInfo, error) {
|
||||
password := authinfo.Password
|
||||
decodedPassword, err := DecodeString(password)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: password}
|
||||
}
|
||||
authinfo.Password = decodedPassword
|
||||
|
||||
token := authinfo.Token
|
||||
decodedToken, err := DecodeString(token)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: token}
|
||||
}
|
||||
authinfo.Token = decodedToken
|
||||
|
||||
clientCert := authinfo.ClientCertificate
|
||||
decodedClientCertificate, err := DecodeString(clientCert)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: clientCert}
|
||||
}
|
||||
authinfo.ClientCertificate = decodedClientCertificate
|
||||
|
||||
clientKey := authinfo.ClientKey
|
||||
decodedClientKey, err := DecodeString(clientKey)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: clientKey}
|
||||
}
|
||||
authinfo.ClientKey = decodedClientKey
|
||||
return authinfo, nil
|
||||
}
|
||||
|
||||
// EncodeAuthInfo returns authInfo with credentials base64 encoded
|
||||
func EncodeAuthInfo(authinfo *clientcmdapi.AuthInfo) *clientcmdapi.AuthInfo {
|
||||
authinfo.Password = EncodeString(authinfo.Password)
|
||||
authinfo.Token = EncodeString(authinfo.Token)
|
||||
authinfo.ClientCertificate = EncodeString(authinfo.ClientCertificate)
|
||||
authinfo.ClientKey = EncodeString(authinfo.ClientKey)
|
||||
return authinfo
|
||||
}
|
||||
|
@ -20,86 +20,6 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// RunSetAuthInfo validates the given command line options and invokes AddAuthInfo/ModifyAuthInfo
|
||||
func RunSetAuthInfo(o *AuthInfoOptions, airconfig *Config, writeToStorage bool) (bool, error) {
|
||||
modified := false
|
||||
err := o.Validate()
|
||||
if err != nil {
|
||||
return modified, err
|
||||
}
|
||||
|
||||
authinfo, err := airconfig.GetAuthInfo(o.Name)
|
||||
if err != nil {
|
||||
var cerr ErrMissingConfig
|
||||
if !errors.As(err, &cerr) {
|
||||
// An error occurred, but it wasn't a "missing" config error.
|
||||
return modified, err
|
||||
}
|
||||
|
||||
// authinfo didn't exist, create it
|
||||
// ignoring the returned added authinfo
|
||||
airconfig.AddAuthInfo(o)
|
||||
} else {
|
||||
// AuthInfo exists, lets update
|
||||
airconfig.ModifyAuthInfo(authinfo, o)
|
||||
modified = true
|
||||
}
|
||||
// Update configuration file just in time persistence approach
|
||||
if writeToStorage {
|
||||
if err := airconfig.PersistConfig(true); err != nil {
|
||||
// Error that it didnt persist the changes
|
||||
return modified, ErrConfigFailed{}
|
||||
}
|
||||
}
|
||||
|
||||
return modified, nil
|
||||
}
|
||||
|
||||
// RunSetCluster validates the given command line options and invokes AddCluster/ModifyCluster
|
||||
func RunSetCluster(o *ClusterOptions, airconfig *Config, writeToStorage bool) (bool, error) {
|
||||
modified := false
|
||||
err := o.Validate()
|
||||
if err != nil {
|
||||
return modified, err
|
||||
}
|
||||
|
||||
cluster, err := airconfig.GetCluster(o.Name, o.ClusterType)
|
||||
if err != nil {
|
||||
var cerr ErrMissingConfig
|
||||
if !errors.As(err, &cerr) {
|
||||
// An error occurred, but it wasn't a "missing" config error.
|
||||
return modified, err
|
||||
}
|
||||
|
||||
// Cluster didn't exist, create it
|
||||
_, err := airconfig.AddCluster(o)
|
||||
if err != nil {
|
||||
return modified, err
|
||||
}
|
||||
modified = false
|
||||
} else {
|
||||
// Cluster exists, lets update
|
||||
_, err := airconfig.ModifyCluster(cluster, o)
|
||||
if err != nil {
|
||||
return modified, err
|
||||
}
|
||||
modified = true
|
||||
}
|
||||
|
||||
// Update configuration file
|
||||
// Just in time persistence approach
|
||||
if writeToStorage {
|
||||
if err := airconfig.PersistConfig(true); err != nil {
|
||||
// Some warning here , that it didnt persist the changes because of this
|
||||
// Or should we float this up
|
||||
// What would it mean? No value.
|
||||
return modified, err
|
||||
}
|
||||
}
|
||||
|
||||
return modified, nil
|
||||
}
|
||||
|
||||
// RunSetContext validates the given command line options and invokes AddContext/ModifyContext
|
||||
func RunSetContext(o *ContextOptions, airconfig *Config, writeToStorage bool) (bool, error) {
|
||||
modified := false
|
||||
|
@ -25,61 +25,6 @@ import (
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
func TestRunSetAuthInfo(t *testing.T) {
|
||||
t.Run("testAddAuthInfo", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
dummyAuthInfoOptions := testutil.DummyAuthInfoOptions()
|
||||
dummyAuthInfoOptions.Name = "second_user"
|
||||
dummyAuthInfoOptions.Token = ""
|
||||
|
||||
modified, err := config.RunSetAuthInfo(dummyAuthInfoOptions, conf, false)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, modified)
|
||||
assert.Contains(t, conf.AuthInfos, "second_user")
|
||||
})
|
||||
|
||||
t.Run("testModifyAuthInfo", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
dummyAuthInfoOptions := testutil.DummyAuthInfoOptions()
|
||||
dummyAuthInfoOptions.Name = "dummy_user"
|
||||
dummyAuthInfoOptions.Password = "testpassword123"
|
||||
dummyAuthInfoOptions.Token = ""
|
||||
|
||||
modified, err := config.RunSetAuthInfo(dummyAuthInfoOptions, conf, false)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, modified)
|
||||
authInfo, err := conf.GetAuthInfo("dummy_user")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, dummyAuthInfoOptions.Password, authInfo.KubeAuthInfo().Password)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunSetCluster(t *testing.T) {
|
||||
t.Run("testAddCluster", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
dummyClusterOptions := testutil.DummyClusterOptions()
|
||||
dummyClusterOptions.Name = "second_cluster"
|
||||
|
||||
modified, err := config.RunSetCluster(dummyClusterOptions, conf, false)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, modified)
|
||||
assert.Contains(t, conf.Clusters, "second_cluster")
|
||||
})
|
||||
|
||||
t.Run("testModifyCluster", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
dummyClusterOptions := testutil.DummyClusterOptions()
|
||||
dummyClusterOptions.Server = "http://123.45.67.890"
|
||||
|
||||
modified, err := config.RunSetCluster(dummyClusterOptions, conf, false)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, modified)
|
||||
assert.Equal(
|
||||
t, "http://123.45.67.890",
|
||||
conf.Clusters["dummy_cluster"].ClusterTypes["ephemeral"].KubeCluster().Server)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunSetContext(t *testing.T) {
|
||||
t.Run("testAddContext", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
@ -95,12 +40,10 @@ func TestRunSetContext(t *testing.T) {
|
||||
t.Run("testModifyContext", func(t *testing.T) {
|
||||
conf := testutil.DummyConfig()
|
||||
dummyContextOptions := testutil.DummyContextOptions()
|
||||
dummyContextOptions.Namespace = "new_namespace"
|
||||
|
||||
modified, err := config.RunSetContext(dummyContextOptions, conf, false)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, modified)
|
||||
assert.Equal(t, "new_namespace", conf.Contexts["dummy_context"].KubeContext().Namespace)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,7 @@ package config_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -35,10 +33,6 @@ const (
|
||||
stringDelta = "_changed"
|
||||
currentContextName = "def_ephemeral"
|
||||
defaultString = "default"
|
||||
newToken = "dummy_token_changed"
|
||||
newPassword = "dummy_password_changed"
|
||||
newCertificate = "dummy_certificate_changed"
|
||||
newKey = "dummy_key_changed"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
@ -56,14 +50,6 @@ func TestString(t *testing.T) {
|
||||
name: "context",
|
||||
stringer: testutil.DummyContext(),
|
||||
},
|
||||
{
|
||||
name: "cluster",
|
||||
stringer: testutil.DummyCluster(),
|
||||
},
|
||||
{
|
||||
name: "authinfo",
|
||||
stringer: testutil.DummyAuthInfo(),
|
||||
},
|
||||
{
|
||||
name: "manifest",
|
||||
stringer: testutil.DummyManifest(),
|
||||
@ -106,11 +92,7 @@ func TestLoadConfig(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
assert.Len(t, conf.Clusters, 6)
|
||||
require.Contains(t, conf.Clusters, "def")
|
||||
assert.Len(t, conf.Clusters["def"].ClusterTypes, 2)
|
||||
assert.Len(t, conf.Contexts, 3)
|
||||
assert.Len(t, conf.AuthInfos, 3)
|
||||
assert.Len(t, conf.Contexts, 4)
|
||||
}
|
||||
|
||||
func TestPersistConfig(t *testing.T) {
|
||||
@ -124,13 +106,7 @@ func TestPersistConfig(t *testing.T) {
|
||||
assert.FileExists(t, conf.LoadedConfigPath())
|
||||
assert.FileExists(t, conf.KubeConfigPath())
|
||||
// Check that the invalid name was changed to a valid one
|
||||
assert.Contains(t, conf.KubeConfig().Clusters, "invalidName_target")
|
||||
|
||||
// Check that the missing cluster was added to the airshipconfig
|
||||
assert.Contains(t, conf.Clusters, "onlyinkubeconf")
|
||||
|
||||
// Check that the "stragglers" were removed from the airshipconfig
|
||||
assert.NotContains(t, conf.Clusters, "straggler")
|
||||
assert.Contains(t, conf.KubeConfig().Clusters, "def_ephemeral")
|
||||
}
|
||||
|
||||
func TestEnsureComplete(t *testing.T) {
|
||||
@ -143,33 +119,9 @@ func TestEnsureComplete(t *testing.T) {
|
||||
config config.Config
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "no clusters defined",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
CurrentContext: "testContext",
|
||||
},
|
||||
expectedErr: config.ErrMissingConfig{What: "At least one cluster needs to be defined"},
|
||||
},
|
||||
{
|
||||
name: "no users defined",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
CurrentContext: "testContext",
|
||||
},
|
||||
expectedErr: config.ErrMissingConfig{What: "At least one Authentication Information (User) needs to be defined"},
|
||||
},
|
||||
{
|
||||
name: "no contexts defined",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
CurrentContext: "testContext",
|
||||
@ -179,8 +131,6 @@ func TestEnsureComplete(t *testing.T) {
|
||||
{
|
||||
name: "no manifests defined",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{},
|
||||
CurrentContext: "testContext",
|
||||
@ -190,8 +140,6 @@ func TestEnsureComplete(t *testing.T) {
|
||||
{
|
||||
name: "current context not defined",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
CurrentContext: "",
|
||||
@ -201,8 +149,6 @@ func TestEnsureComplete(t *testing.T) {
|
||||
{
|
||||
name: "no context for current context",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{"DIFFERENT_CONTEXT": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
CurrentContext: "testContext",
|
||||
@ -212,8 +158,6 @@ func TestEnsureComplete(t *testing.T) {
|
||||
{
|
||||
name: "no manifest for current context",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"DIFFERENT_MANIFEST": {}},
|
||||
CurrentContext: "testContext",
|
||||
@ -223,11 +167,9 @@ func TestEnsureComplete(t *testing.T) {
|
||||
{
|
||||
name: "complete config",
|
||||
config: config.Config{
|
||||
Clusters: map[string]*config.ClusterPurpose{"testCluster": {}},
|
||||
AuthInfos: map[string]*config.AuthInfo{"testAuthInfo": {}},
|
||||
EncryptionConfigs: map[string]*config.EncryptionConfig{"testEncryptionConfig": {}},
|
||||
Contexts: map[string]*config.Context{"testContext": {Manifest: "testManifest"}},
|
||||
Manifests: map[string]*config.Manifest{"testManifest": {}},
|
||||
EncryptionConfigs: map[string]*config.EncryptionConfig{"testEncryptionConfig": {}},
|
||||
CurrentContext: "testContext",
|
||||
},
|
||||
expectedErr: nil,
|
||||
@ -247,17 +189,13 @@ func TestCurrentContextManagementConfig(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusterName := "def"
|
||||
clusterType := "ephemeral"
|
||||
|
||||
managementConfig, err := conf.CurrentContextManagementConfig()
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, managementConfig)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Clusters[clusterName].ClusterTypes[clusterType].ManagementConfiguration = defaultString
|
||||
conf.Contexts[currentContextName].ManagementConfiguration = defaultString
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
conf.Contexts[currentContextName].KubeContext().Cluster = clusterName
|
||||
|
||||
managementConfig, err = conf.CurrentContextManagementConfig()
|
||||
require.NoError(t, err)
|
||||
@ -308,42 +246,12 @@ func TestSetKubeConfigPath(t *testing.T) {
|
||||
assert.Equal(t, testPath, conf.KubeConfigPath())
|
||||
}
|
||||
|
||||
func TestModifyCluster(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
co := testutil.DummyClusterOptions()
|
||||
cluster, err := conf.AddCluster(co)
|
||||
require.NoError(t, err)
|
||||
|
||||
co.Server += stringDelta
|
||||
co.InsecureSkipTLSVerify = true
|
||||
co.EmbedCAData = true
|
||||
mcluster, err := conf.ModifyCluster(cluster, co)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, conf.Clusters[co.Name].ClusterTypes[co.ClusterType].KubeCluster().Server, co.Server)
|
||||
assert.EqualValues(t, conf.Clusters[co.Name].ClusterTypes[co.ClusterType], mcluster)
|
||||
|
||||
// Error case
|
||||
co.CertificateAuthority = "unknown"
|
||||
_, err = conf.ModifyCluster(cluster, co)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGetClusters(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusters := conf.GetClusters()
|
||||
assert.Len(t, clusters, 6)
|
||||
}
|
||||
|
||||
func TestGetContexts(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
contexts := conf.GetContexts()
|
||||
assert.Len(t, contexts, 3)
|
||||
assert.Len(t, contexts, 4)
|
||||
}
|
||||
|
||||
func TestGetContext(t *testing.T) {
|
||||
@ -355,7 +263,6 @@ func TestGetContext(t *testing.T) {
|
||||
|
||||
// Test Positives
|
||||
assert.EqualValues(t, context.NameInKubeconf, "def_ephemeral")
|
||||
assert.EqualValues(t, context.KubeContext().Cluster, "def_ephemeral")
|
||||
|
||||
// Test Wrong Cluster
|
||||
_, err = conf.GetContext("unknown")
|
||||
@ -378,14 +285,8 @@ func TestModifyContext(t *testing.T) {
|
||||
co := testutil.DummyContextOptions()
|
||||
context := conf.AddContext(co)
|
||||
|
||||
co.Namespace += stringDelta
|
||||
co.Cluster += stringDelta
|
||||
co.AuthInfo += stringDelta
|
||||
co.Manifest += stringDelta
|
||||
conf.ModifyContext(context, co)
|
||||
assert.EqualValues(t, conf.Contexts[co.Name].KubeContext().Namespace, co.Namespace)
|
||||
assert.EqualValues(t, conf.Contexts[co.Name].KubeContext().Cluster, co.Cluster)
|
||||
assert.EqualValues(t, conf.Contexts[co.Name].KubeContext().AuthInfo, co.AuthInfo)
|
||||
assert.EqualValues(t, conf.Contexts[co.Name].Manifest, co.Manifest)
|
||||
assert.EqualValues(t, conf.Contexts[co.Name], context)
|
||||
}
|
||||
@ -408,55 +309,16 @@ func TestGetCurrentContext(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestCurrentContextCluster(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusterName := "def"
|
||||
clusterType := "ephemeral"
|
||||
|
||||
cluster, err := conf.CurrentContextCluster()
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, cluster)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
conf.Contexts[currentContextName].KubeContext().Cluster = clusterName
|
||||
|
||||
cluster, err = conf.CurrentContextCluster()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, conf.Clusters[clusterName].ClusterTypes[clusterType], cluster)
|
||||
}
|
||||
|
||||
func TestCurrentContextAuthInfo(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
authInfo, err := conf.CurrentContextAuthInfo()
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, authInfo)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
|
||||
authInfo, err = conf.CurrentContextAuthInfo()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, conf.AuthInfos["k-admin"], authInfo)
|
||||
}
|
||||
|
||||
func TestCurrentContextManifest(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusterName := "def"
|
||||
|
||||
manifest, err := conf.CurrentContextManifest()
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, manifest)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
conf.Contexts[currentContextName].KubeContext().Cluster = clusterName
|
||||
|
||||
manifest, err = conf.CurrentContextManifest()
|
||||
require.NoError(t, err)
|
||||
@ -467,15 +329,12 @@ func TestCurrentTargetPath(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusterName := "def"
|
||||
|
||||
manifest, err := conf.CurrentContextManifest()
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, manifest)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
conf.Contexts[currentContextName].KubeContext().Cluster = clusterName
|
||||
|
||||
targetPath, err := conf.CurrentContextTargetPath()
|
||||
require.NoError(t, err)
|
||||
@ -486,15 +345,12 @@ func TestCurrentContextEntryPoint(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
clusterName := "def"
|
||||
|
||||
entryPoint, err := conf.CurrentContextEntryPoint(defaultString)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, "", entryPoint)
|
||||
|
||||
conf.CurrentContext = currentContextName
|
||||
conf.Contexts[currentContextName].Manifest = defaultString
|
||||
conf.Contexts[currentContextName].KubeContext().Cluster = clusterName
|
||||
|
||||
entryPoint, err = conf.CurrentContextEntryPoint(defaultString)
|
||||
assert.Equal(t, config.ErrMissingPhaseDocument{PhaseName: defaultString}, err)
|
||||
@ -661,144 +517,6 @@ func TestNewClusterComplexNameFromKubeClusterName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImport(t *testing.T) {
|
||||
conf, cleanupConfig := testutil.InitConfig(t)
|
||||
defer cleanupConfig(t)
|
||||
|
||||
kubeDir, cleanupKubeConfig := testutil.TempDir(t, "airship-import-tests")
|
||||
defer cleanupKubeConfig(t)
|
||||
|
||||
kubeConfigPath := filepath.Join(kubeDir, "config")
|
||||
//nolint: lll
|
||||
kubeConfigContent := `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://1.2.3.4:9000
|
||||
name: cluster_target
|
||||
- cluster:
|
||||
server: https://1.2.3.4:9001
|
||||
name: dummycluster_ephemeral
|
||||
- cluster:
|
||||
server: https://1.2.3.4:9002
|
||||
name: def_target
|
||||
- cluster:
|
||||
server: https://1.2.3.4:9003
|
||||
name: noncomplex
|
||||
contexts:
|
||||
- context:
|
||||
cluster: cluster_target
|
||||
user: cluster-admin
|
||||
name: cluster-admin@cluster
|
||||
- context:
|
||||
cluster: dummycluster_ephemeral
|
||||
user: kubernetes-admin
|
||||
name: dummy_cluster
|
||||
- context:
|
||||
cluster: dummycluster_ephemeral
|
||||
user: kubernetes-admin
|
||||
name: def_target
|
||||
- context:
|
||||
cluster: noncomplex
|
||||
user: kubernetes-admin
|
||||
name: noncomplex
|
||||
current-context: dummy_cluster
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: cluster-admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
- name: kubernetes-admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
- name: def-user
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
`
|
||||
err := ioutil.WriteFile(kubeConfigPath, []byte(kubeConfigContent), 0600)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conf.ImportFromKubeConfig(kubeConfigPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("importClusters", func(t *testing.T) {
|
||||
// Verify that only 3 clusters have been added (original 5 plus 3 new clusters)
|
||||
// This is important since the above kubeconfig actually has 4
|
||||
// clusters, but one was already defined in the airship config
|
||||
assert.Len(t, conf.Clusters, 6+3)
|
||||
|
||||
// verify that the new clusters have been added to the config
|
||||
_, err := conf.GetCluster("cluster", config.Target)
|
||||
assert.NoError(t, err)
|
||||
_, err = conf.GetCluster("dummycluster", config.Ephemeral)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// verify that the "noncomplex" cluster was added as a target cluster
|
||||
_, err = conf.GetCluster("noncomplex", config.Target)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("importContexts", func(t *testing.T) {
|
||||
// Verify that only 3 contexts have been added (original 3 plus 3 new contexts)
|
||||
// This is important since the above kubeconfig actually has 4
|
||||
// contexts, but one was already defined in the airship config
|
||||
assert.Len(t, conf.Contexts, 3+3)
|
||||
|
||||
// verify that the new contexts have been added to the config
|
||||
_, err := conf.GetContext("cluster-admin@cluster")
|
||||
assert.NoError(t, err)
|
||||
_, err = conf.GetContext("dummy_cluster")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// verify that the "noncomplex" context refers to the proper target "noncomplex" cluster
|
||||
noncomplex, err := conf.GetContext("noncomplex")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "noncomplex_target", noncomplex.NameInKubeconf)
|
||||
})
|
||||
|
||||
t.Run("importAuthInfos", func(t *testing.T) {
|
||||
// Verify that only 2 users have been added (original 3 plus 2 new users)
|
||||
// This is important since the above kubeconfig actually has 3
|
||||
// users, but one was already defined in the airship config
|
||||
assert.Len(t, conf.AuthInfos, 3+2)
|
||||
|
||||
// verify that the new users have been added to the config
|
||||
_, err := conf.GetAuthInfo("cluster-admin")
|
||||
assert.NoError(t, err)
|
||||
_, err = conf.GetAuthInfo("kubernetes-admin")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestImportErrors(t *testing.T) {
|
||||
conf, cleanupConfig := testutil.InitConfig(t)
|
||||
defer cleanupConfig(t)
|
||||
|
||||
t.Run("nonexistent kubeConfig", func(t *testing.T) {
|
||||
err := conf.ImportFromKubeConfig("./non/existent/file/path")
|
||||
assert.Contains(t, err.Error(), "no such file or directory")
|
||||
})
|
||||
|
||||
t.Run("malformed kubeConfig", func(t *testing.T) {
|
||||
kubeDir, cleanupKubeConfig := testutil.TempDir(t, "airship-import-tests")
|
||||
defer cleanupKubeConfig(t)
|
||||
|
||||
kubeConfigPath := filepath.Join(kubeDir, "config")
|
||||
//nolint: lll
|
||||
kubeConfigContent := "malformed content"
|
||||
|
||||
err := ioutil.WriteFile(kubeConfigPath, []byte(kubeConfigContent), 0600)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conf.ImportFromKubeConfig(kubeConfigPath)
|
||||
assert.Contains(t, err.Error(), "json parse error")
|
||||
})
|
||||
}
|
||||
|
||||
func TestManagementConfigurationByName(t *testing.T) {
|
||||
conf, cleanupConfig := testutil.InitConfig(t)
|
||||
defer cleanupConfig(t)
|
||||
|
@ -18,8 +18,8 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@ -37,8 +37,8 @@ type Context struct {
|
||||
// +optional
|
||||
EncryptionConfig string `json:"encryptionConfig,omitempty"`
|
||||
|
||||
// KubeConfig Context Object
|
||||
context *api.Context
|
||||
// Management configuration which will be used for all hosts in the cluster
|
||||
ManagementConfiguration string `json:"managementConfiguration"`
|
||||
}
|
||||
|
||||
func (c *Context) String() string {
|
||||
@ -46,12 +46,10 @@ func (c *Context) String() string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
kcluster := c.KubeContext()
|
||||
kyaml, err := yaml.Marshal(&kcluster)
|
||||
if err != nil {
|
||||
return string(cyaml)
|
||||
}
|
||||
return fmt.Sprintf("%s\n%s", string(cyaml), string(kyaml))
|
||||
return string(cyaml)
|
||||
}
|
||||
|
||||
// PrettyString returns cluster name in a formatted string
|
||||
@ -60,16 +58,6 @@ func (c *Context) PrettyString() string {
|
||||
return fmt.Sprintf("Context: %s\n%s\n", clusterName.Name, c)
|
||||
}
|
||||
|
||||
// KubeContext returns kube context object
|
||||
func (c *Context) KubeContext() *api.Context {
|
||||
return c.context
|
||||
}
|
||||
|
||||
// SetKubeContext updates kube contect with given context details
|
||||
func (c *Context) SetKubeContext(kc *api.Context) {
|
||||
c.context = kc
|
||||
}
|
||||
|
||||
// ClusterType returns cluster type by extracting the type portion from
|
||||
// the complex cluster name
|
||||
func (c *Context) ClusterType() string {
|
||||
@ -81,3 +69,48 @@ func (c *Context) ClusterType() string {
|
||||
func (c *Context) ClusterName() string {
|
||||
return NewClusterComplexNameFromKubeClusterName(c.NameInKubeconf).Name
|
||||
}
|
||||
|
||||
// ClusterComplexName holds the complex cluster name information
|
||||
// Encapsulates the different operations around using it.
|
||||
type ClusterComplexName struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
// NewClusterComplexName returns a ClusterComplexName with the given name and type.
|
||||
func NewClusterComplexName(clusterName, clusterType string) ClusterComplexName {
|
||||
return ClusterComplexName{
|
||||
Name: clusterName,
|
||||
Type: clusterType,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClusterComplexNameFromKubeClusterName takes the name of a cluster in a
|
||||
// format which might be found in a kubeconfig file. This may be a simple
|
||||
// string (e.g. myCluster), or it may be prepended with the type of the cluster
|
||||
// (e.g. myCluster_target)
|
||||
//
|
||||
// If a valid cluster type was appended, the returned ClusterComplexName will
|
||||
// have that type. If no cluster type is provided, the
|
||||
// AirshipDefaultClusterType will be used.
|
||||
func NewClusterComplexNameFromKubeClusterName(kubeClusterName string) ClusterComplexName {
|
||||
parts := strings.Split(kubeClusterName, AirshipClusterNameSeparator)
|
||||
|
||||
if len(parts) == 1 {
|
||||
return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType)
|
||||
}
|
||||
|
||||
// kubeClusterName matches the format myCluster_something.
|
||||
// Let's check if "something" is a clusterType.
|
||||
potentialType := parts[len(parts)-1]
|
||||
for _, ct := range AllClusterTypes {
|
||||
if potentialType == ct {
|
||||
// Rejoin the parts in the case of "my_cluster_etc_etc_<clusterType>"
|
||||
name := strings.Join(parts[:len(parts)-1], AirshipClusterNameSeparator)
|
||||
return NewClusterComplexName(name, potentialType)
|
||||
}
|
||||
}
|
||||
|
||||
// "something" is not a valid clusterType, so just use the default
|
||||
return NewClusterComplexName(kubeClusterName, AirshipDefaultClusterType)
|
||||
}
|
||||
|
@ -163,12 +163,12 @@ func (e ErrMissingCurrentContext) Error() string {
|
||||
|
||||
// ErrMissingManagementConfiguration means the management configuration was not defined for the active cluster.
|
||||
type ErrMissingManagementConfiguration struct {
|
||||
cluster *Cluster
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (e ErrMissingManagementConfiguration) Error() string {
|
||||
return fmt.Sprintf("Management configuration %s for cluster %s undefined.", e.cluster.ManagementConfiguration,
|
||||
e.cluster.NameInKubeconf)
|
||||
return fmt.Sprintf("Management configuration %s for cluster %s undefined.", e.context.ManagementConfiguration,
|
||||
e.context.NameInKubeconf)
|
||||
}
|
||||
|
||||
// ErrMissingPrimaryRepo returned when Primary Repository is not set in context manifest
|
||||
@ -206,14 +206,6 @@ func (e ErrConflictingClusterOptions) Error() string {
|
||||
return "Specifying certificate-authority and insecure-skip-tls-verify mode is not allowed at the same time."
|
||||
}
|
||||
|
||||
// ErrEmptyClusterName returned when empty cluster name is set
|
||||
type ErrEmptyClusterName struct {
|
||||
}
|
||||
|
||||
func (e ErrEmptyClusterName) Error() string {
|
||||
return "Cluster name must not be empty."
|
||||
}
|
||||
|
||||
// ErrConflictingContextOptions returned when both context and --current is set at same time
|
||||
type ErrConflictingContextOptions struct {
|
||||
}
|
||||
|
@ -22,39 +22,15 @@ import (
|
||||
"opendev.org/airship/airshipctl/pkg/errors"
|
||||
)
|
||||
|
||||
// AuthInfoOptions holds all configurable options for
|
||||
// authentication information or credential
|
||||
type AuthInfoOptions struct {
|
||||
Name string
|
||||
ClientCertificate string
|
||||
ClientKey string
|
||||
Token string
|
||||
Username string
|
||||
Password string
|
||||
EmbedCertData bool
|
||||
}
|
||||
|
||||
// ContextOptions holds all configurable options for context
|
||||
type ContextOptions struct {
|
||||
Name string
|
||||
ClusterType string
|
||||
CurrentContext bool
|
||||
Cluster string
|
||||
AuthInfo string
|
||||
Manifest string
|
||||
EncryptionConfig string
|
||||
Namespace string
|
||||
Current bool
|
||||
}
|
||||
|
||||
// ClusterOptions holds all configurable options for cluster configuration
|
||||
type ClusterOptions struct {
|
||||
Name string
|
||||
ClusterType string
|
||||
Server string
|
||||
InsecureSkipTLSVerify bool
|
||||
CertificateAuthority string
|
||||
EmbedCAData bool
|
||||
Name string
|
||||
ClusterType string
|
||||
CurrentContext bool
|
||||
Manifest string
|
||||
Current bool
|
||||
ManagementConfiguration string
|
||||
EncryptionConfig string
|
||||
}
|
||||
|
||||
// ManifestOptions holds all configurable options for manifest configuration
|
||||
@ -86,33 +62,6 @@ type EncryptionConfigOptions struct {
|
||||
// is possible to create (and validate) these objects without using the command
|
||||
// line.
|
||||
|
||||
// Validate checks for the possible authentication values and returns
|
||||
// Error when invalid value or incompatible choice of values given
|
||||
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 != "") {
|
||||
return ErrConflictingAuthOptions{}
|
||||
}
|
||||
|
||||
if !o.EmbedCertData {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := checkExists("client-certificate", o.ClientCertificate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkExists("client-key", o.ClientKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks for the possible context option values and returns
|
||||
// Error when invalid value or incompatible choice of values given
|
||||
func (o *ContextOptions) Validate() error {
|
||||
@ -129,58 +78,10 @@ func (o *ContextOptions) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the cluster-type was specified, verify that it's valid
|
||||
if o.ClusterType != "" {
|
||||
if err := ValidClusterType(o.ClusterType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Manifest, Cluster could be validated against the existing config maps
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks for the possible cluster option values and returns
|
||||
// Error when invalid value or incompatible choice of values given
|
||||
func (o *ClusterOptions) Validate() error {
|
||||
if o.Name == "" {
|
||||
return ErrEmptyClusterName{}
|
||||
}
|
||||
|
||||
err := ValidClusterType(o.ClusterType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.InsecureSkipTLSVerify && o.CertificateAuthority != "" {
|
||||
return ErrConflictingClusterOptions{}
|
||||
}
|
||||
|
||||
if !o.EmbedCAData {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := checkExists("certificate-authority", o.CertificateAuthority); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkExists(flagName, path string) error {
|
||||
if path == "" {
|
||||
return ErrMissingFlag{FlagName: flagName}
|
||||
}
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return ErrCheckFile{
|
||||
FlagName: flagName,
|
||||
Path: path,
|
||||
InternalErr: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks for the possible manifest option values and returns
|
||||
// Error when invalid value or incompatible choice of values given
|
||||
func (o *ManifestOptions) Validate() error {
|
||||
@ -247,3 +148,17 @@ func (o EncryptionConfigOptions) backedByFileSystem() bool {
|
||||
func (o EncryptionConfigOptions) backedByAPIServer() bool {
|
||||
return o.KeySecretName != "" || o.KeySecretNamespace != ""
|
||||
}
|
||||
|
||||
func checkExists(flagName, path string) error {
|
||||
if path == "" {
|
||||
return ErrMissingFlag{FlagName: flagName}
|
||||
}
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return ErrCheckFile{
|
||||
FlagName: flagName,
|
||||
Path: path,
|
||||
InternalErr: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -17,83 +17,13 @@ limitations under the License.
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
)
|
||||
|
||||
func TestAuthInfoOptionsValidate(t *testing.T) {
|
||||
aRealFile, err := ioutil.TempFile("", "a-real-file")
|
||||
require.NoError(t, err)
|
||||
|
||||
aRealFilename := aRealFile.Name()
|
||||
defer os.Remove(aRealFilename)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
testOptions config.AuthInfoOptions
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "TokenAndUserPass",
|
||||
testOptions: config.AuthInfoOptions{
|
||||
Token: "testToken",
|
||||
Username: "testUser",
|
||||
Password: "testPassword",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "DontEmbed",
|
||||
testOptions: config.AuthInfoOptions{
|
||||
EmbedCertData: false,
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithoutCert",
|
||||
testOptions: config.AuthInfoOptions{
|
||||
EmbedCertData: true,
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithoutClientKey",
|
||||
testOptions: config.AuthInfoOptions{
|
||||
EmbedCertData: true,
|
||||
ClientCertificate: aRealFilename,
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithCertAndClientKey",
|
||||
testOptions: config.AuthInfoOptions{
|
||||
EmbedCertData: true,
|
||||
ClientCertificate: aRealFilename,
|
||||
ClientKey: aRealFilename,
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(subTest *testing.T) {
|
||||
err := tt.testOptions.Validate()
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextOptionsValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -107,14 +37,6 @@ func TestContextOptionsValidate(t *testing.T) {
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidClusterType",
|
||||
testOptions: config.ContextOptions{
|
||||
Name: "testContext",
|
||||
ClusterType: "badType",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "SettingCurrentContext",
|
||||
testOptions: config.ContextOptions{
|
||||
@ -152,93 +74,3 @@ func TestContextOptionsValidate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClusterOptionsValidate(t *testing.T) {
|
||||
aRealfile, err := ioutil.TempFile("", "a-real-file")
|
||||
require.NoError(t, err)
|
||||
|
||||
aRealFilename := aRealfile.Name()
|
||||
defer os.Remove(aRealFilename)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
testOptions config.ClusterOptions
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "MissingName",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidClusterType",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "badType",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "InsecureSkipTLSVerifyAndCertificateAuthority",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "target",
|
||||
InsecureSkipTLSVerify: true,
|
||||
CertificateAuthority: "cert_file",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "DontEmbed",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "target",
|
||||
EmbedCAData: false,
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithoutCA",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "target",
|
||||
EmbedCAData: true,
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithFaultyCA",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "target",
|
||||
EmbedCAData: true,
|
||||
CertificateAuthority: "not-a-real-file",
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "EmbedWithGoodCA",
|
||||
testOptions: config.ClusterOptions{
|
||||
Name: "testCluster",
|
||||
ClusterType: "target",
|
||||
EmbedCAData: true,
|
||||
CertificateAuthority: aRealFilename,
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(subTest *testing.T) {
|
||||
err := tt.testOptions.Validate()
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
6
pkg/config/testdata/authinfo-string.yaml
vendored
6
pkg/config/testdata/authinfo-string.yaml
vendored
@ -1,6 +0,0 @@
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: ZHVtbXlfY2VydGlmaWNhdGU=
|
||||
client-key: ZHVtbXlfa2V5
|
||||
password: ZHVtbXlfcGFzc3dvcmQ=
|
||||
token: ZHVtbXlfdG9rZW4=
|
||||
username: dummy_username
|
6
pkg/config/testdata/cluster-string.yaml
vendored
6
pkg/config/testdata/cluster-string.yaml
vendored
@ -1,6 +0,0 @@
|
||||
clusterKubeconf: dummy_cluster_target
|
||||
managementConfiguration: dummy_management_config
|
||||
|
||||
LocationOfOrigin: ""
|
||||
certificate-authority: dummy_ca
|
||||
server: http://dummy.server
|
12
pkg/config/testdata/config-string.yaml
vendored
12
pkg/config/testdata/config-string.yaml
vendored
@ -1,17 +1,9 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
clusters:
|
||||
dummy_cluster:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
clusterKubeconf: dummy_cluster_ephemeral
|
||||
managementConfiguration: dummy_management_config
|
||||
target:
|
||||
clusterKubeconf: dummy_cluster_target
|
||||
managementConfiguration: dummy_management_config
|
||||
contexts:
|
||||
dummy_context:
|
||||
contextKubeconf: dummy_cluster_ephemeral
|
||||
encryptionConfig: dummy_encryption_config
|
||||
managementConfiguration: dummy_management_config
|
||||
manifest: dummy_manifest
|
||||
currentContext: dummy_context
|
||||
encryptionConfigs:
|
||||
@ -43,5 +35,3 @@ manifests:
|
||||
permissions:
|
||||
DirectoryPermission: 488
|
||||
FilePermission: 416
|
||||
users:
|
||||
dummy_user: {}
|
||||
|
6
pkg/config/testdata/context-string.yaml
vendored
6
pkg/config/testdata/context-string.yaml
vendored
@ -1,8 +1,4 @@
|
||||
contextKubeconf: dummy_cluster_ephemeral
|
||||
encryptionConfig: dummy_encryption_config
|
||||
managementConfiguration: dummy_management_config
|
||||
manifest: dummy_manifest
|
||||
|
||||
LocationOfOrigin: ""
|
||||
cluster: dummy_cluster_ephemeral
|
||||
namespace: dummy_namespace
|
||||
user: dummy_user
|
||||
|
@ -1,8 +0,0 @@
|
||||
Cluster: dummy_cluster
|
||||
target:
|
||||
clusterKubeconf: dummy_cluster_target
|
||||
managementConfiguration: dummy_management_config
|
||||
|
||||
LocationOfOrigin: ""
|
||||
certificate-authority: dummy_ca
|
||||
server: http://dummy.server
|
@ -27,15 +27,14 @@ func NewConfig() *Config {
|
||||
return &Config{
|
||||
Kind: AirshipConfigKind,
|
||||
APIVersion: AirshipConfigAPIVersion,
|
||||
Clusters: make(map[string]*ClusterPurpose),
|
||||
Permissions: Permissions{
|
||||
DirectoryPermission: AirshipDefaultDirectoryPermission,
|
||||
FilePermission: AirshipDefaultFilePermission,
|
||||
},
|
||||
AuthInfos: make(map[string]*AuthInfo),
|
||||
Contexts: map[string]*Context{
|
||||
AirshipDefaultContext: {
|
||||
Manifest: AirshipDefaultManifest,
|
||||
Manifest: AirshipDefaultManifest,
|
||||
ManagementConfiguration: AirshipDefaultManagementConfiguration,
|
||||
},
|
||||
},
|
||||
CurrentContext: AirshipDefaultContext,
|
||||
@ -87,14 +86,6 @@ func NewContext() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
||||
// NewCluster is a convenience function that returns a new Cluster
|
||||
func NewCluster() *Cluster {
|
||||
return &Cluster{
|
||||
NameInKubeconf: "",
|
||||
ManagementConfiguration: AirshipDefaultManagementConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
// NewManifest is a convenience function that returns a new Manifest
|
||||
// object with non-nil maps
|
||||
func NewManifest() *Manifest {
|
||||
@ -114,11 +105,6 @@ func NewRepository() *Repository {
|
||||
}
|
||||
}
|
||||
|
||||
// NewAuthInfo is a convenience function that returns a new AuthInfo
|
||||
func NewAuthInfo() *AuthInfo {
|
||||
return &AuthInfo{}
|
||||
}
|
||||
|
||||
// EncodeString returns the base64 encoding of given string
|
||||
func EncodeString(given string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(given))
|
||||
|
@ -60,7 +60,6 @@ func TestDeploy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedErrorString string
|
||||
clusterPurposes map[string]*config.ClusterPurpose
|
||||
phaseName string
|
||||
events []applyevent.Event
|
||||
}{
|
||||
@ -95,9 +94,6 @@ func TestDeploy(t *testing.T) {
|
||||
ao.Applier = cliApplier
|
||||
ao.EventChannel = ch
|
||||
}
|
||||
if tt.clusterPurposes != nil {
|
||||
rs.Clusters = tt.clusterPurposes
|
||||
}
|
||||
if tt.phaseName != "" {
|
||||
ao.PhaseName = tt.phaseName
|
||||
}
|
||||
|
22
pkg/phase/apply/testdata/config.yaml
vendored
22
pkg/phase/apply/testdata/config.yaml
vendored
@ -1,25 +1,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
dummy_bootstrap_config:
|
||||
container:
|
||||
volume: /tmp/airship:/config
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
containerRuntime: docker
|
||||
builder:
|
||||
userDataFileName: user-data
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
remoteDirect:
|
||||
isoUrl: http://localhost:8099/ubuntu-focal.iso
|
||||
clusters:
|
||||
dummycluster:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
bootstrapInfo: dummy_bootstrap_config
|
||||
clusterKubeconf: dummycluster_ephemeral
|
||||
contexts:
|
||||
dummy_cluster:
|
||||
contextKubeconf: dummy_cluster
|
||||
contextKubeconf: dummycluster_ephemeral
|
||||
manifest: dummy_manifest
|
||||
currentContext: dummy_cluster
|
||||
kind: Config
|
||||
@ -39,5 +21,3 @@ manifests:
|
||||
url: http://dummy.url.com/primary.git
|
||||
subPath: primary/site/test-site
|
||||
targetPath: testdata
|
||||
users:
|
||||
dummy_user: {}
|
23
pkg/phase/testdata/airshipconfig.yaml
vendored
23
pkg/phase/testdata/airshipconfig.yaml
vendored
@ -1,26 +1,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
dummy_bootstrap_config:
|
||||
container:
|
||||
volume: /tmp/airship:/config
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
containerRuntime: docker
|
||||
builder:
|
||||
userDataFileName: user-data
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
remoteDirect:
|
||||
isoUrl: http://localhost:8099/ubuntu-focal.iso
|
||||
remoteType: redfish
|
||||
clusters:
|
||||
dummycluster:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
bootstrapInfo: dummy_bootstrap_config
|
||||
clusterKubeconf: dummycluster_ephemeral
|
||||
contexts:
|
||||
dummy_cluster:
|
||||
contextKubeconf: dummy_cluster
|
||||
contextKubeconf: dummycluster_ephemeral
|
||||
manifest: dummy_manifest
|
||||
currentContext: dummy_cluster
|
||||
kind: Config
|
||||
@ -41,5 +22,3 @@ manifests:
|
||||
tag: v1.0.1
|
||||
url: http://dummy.url.com/primary.git
|
||||
subPath: valid_site
|
||||
users:
|
||||
dummy_user: {}
|
22
testdata/k8s/config.yaml
vendored
22
testdata/k8s/config.yaml
vendored
@ -1,24 +1,4 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
default:
|
||||
builder:
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
userDataFileName: user-data
|
||||
container:
|
||||
containerRuntime: docker
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
volume: /srv/iso:/config
|
||||
remoteDirect:
|
||||
isoUrl: http://localhost:8099/ubuntu-focal.iso
|
||||
clusters:
|
||||
default:
|
||||
clusterType:
|
||||
target:
|
||||
bootstrapInfo: ""
|
||||
clusterKubeconf: default_target
|
||||
kubernetes:
|
||||
clusterType: {}
|
||||
contexts:
|
||||
default:
|
||||
contextKubeconf: default_target
|
||||
@ -36,5 +16,3 @@ manifests:
|
||||
tag: ""
|
||||
url: https://opendev.org/airship/treasuremap
|
||||
targetPath: /tmp/default
|
||||
users:
|
||||
admin: {}
|
||||
|
@ -36,12 +36,6 @@ func DummyConfig() *config.Config {
|
||||
conf := &config.Config{
|
||||
Kind: config.AirshipConfigKind,
|
||||
APIVersion: config.AirshipConfigAPIVersion,
|
||||
Clusters: map[string]*config.ClusterPurpose{
|
||||
"dummy_cluster": DummyClusterPurpose(),
|
||||
},
|
||||
AuthInfos: map[string]*config.AuthInfo{
|
||||
"dummy_user": DummyAuthInfo(),
|
||||
},
|
||||
Permissions: config.Permissions{
|
||||
DirectoryPermission: config.AirshipDefaultDirectoryPermission,
|
||||
FilePermission: config.AirshipDefaultFilePermission,
|
||||
@ -61,10 +55,6 @@ func DummyConfig() *config.Config {
|
||||
CurrentContext: "dummy_context",
|
||||
}
|
||||
conf.SetKubeConfig(kubeconfig.NewConfig())
|
||||
|
||||
dummyCluster := conf.Clusters["dummy_cluster"]
|
||||
conf.KubeConfig().Clusters["dummy_cluster_target"] = dummyCluster.ClusterTypes[config.Target].KubeCluster()
|
||||
conf.KubeConfig().Clusters["dummy_cluster_ephemeral"] = dummyCluster.ClusterTypes[config.Ephemeral].KubeCluster()
|
||||
return conf
|
||||
}
|
||||
|
||||
@ -73,26 +63,7 @@ func DummyContext() *config.Context {
|
||||
c := config.NewContext()
|
||||
c.NameInKubeconf = "dummy_cluster_ephemeral"
|
||||
c.Manifest = "dummy_manifest"
|
||||
context := kubeconfig.NewContext()
|
||||
context.Namespace = "dummy_namespace"
|
||||
context.AuthInfo = "dummy_user"
|
||||
context.Cluster = "dummy_cluster_ephemeral"
|
||||
c.EncryptionConfig = "dummy_encryption_config"
|
||||
c.SetKubeContext(context)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// DummyCluster creates a Cluster config object for unit testing
|
||||
func DummyCluster() *config.Cluster {
|
||||
c := config.NewCluster()
|
||||
|
||||
cluster := kubeconfig.NewCluster()
|
||||
cluster.Server = "http://dummy.server"
|
||||
cluster.InsecureSkipTLSVerify = false
|
||||
cluster.CertificateAuthority = "dummy_ca"
|
||||
c.SetKubeCluster(cluster)
|
||||
c.NameInKubeconf = "dummy_cluster_target"
|
||||
c.ManagementConfiguration = "dummy_management_config"
|
||||
return c
|
||||
}
|
||||
@ -140,29 +111,6 @@ func DummyRepoCheckout() *config.RepoCheckout {
|
||||
}
|
||||
}
|
||||
|
||||
// DummyAuthInfo creates a AuthInfo config object for unit testing
|
||||
func DummyAuthInfo() *config.AuthInfo {
|
||||
a := config.NewAuthInfo()
|
||||
authinfo := kubeconfig.NewAuthInfo()
|
||||
authinfo.Username = "dummy_username"
|
||||
authinfo.Password = "dummy_password"
|
||||
authinfo.ClientCertificate = "dummy_certificate"
|
||||
authinfo.ClientKey = "dummy_key"
|
||||
authinfo.Token = "dummy_token"
|
||||
encodedAuthInfo := config.EncodeAuthInfo(authinfo)
|
||||
a.SetKubeAuthInfo(encodedAuthInfo)
|
||||
return a
|
||||
}
|
||||
|
||||
// DummyClusterPurpose creates ClusterPurpose config object for unit testing
|
||||
func DummyClusterPurpose() *config.ClusterPurpose {
|
||||
cp := config.NewClusterPurpose()
|
||||
cp.ClusterTypes["ephemeral"] = DummyCluster()
|
||||
cp.ClusterTypes["ephemeral"].NameInKubeconf = "dummy_cluster_ephemeral"
|
||||
cp.ClusterTypes["target"] = DummyCluster()
|
||||
return cp
|
||||
}
|
||||
|
||||
// InitConfig creates a Config object meant for testing.
|
||||
//
|
||||
// The returned config object will be associated with real files stored in a
|
||||
@ -188,46 +136,17 @@ func InitConfig(t *testing.T) (conf *config.Config, cleanup func(*testing.T)) {
|
||||
return conf, cleanup
|
||||
}
|
||||
|
||||
// DummyClusterOptions creates ClusterOptions config object
|
||||
// for unit testing
|
||||
func DummyClusterOptions() *config.ClusterOptions {
|
||||
co := &config.ClusterOptions{}
|
||||
co.Name = "dummy_cluster"
|
||||
co.ClusterType = config.Ephemeral
|
||||
co.Server = "http://1.1.1.1"
|
||||
co.InsecureSkipTLSVerify = false
|
||||
co.CertificateAuthority = ""
|
||||
co.EmbedCAData = false
|
||||
|
||||
return co
|
||||
}
|
||||
|
||||
// DummyContextOptions creates ContextOptions config object
|
||||
// for unit testing
|
||||
func DummyContextOptions() *config.ContextOptions {
|
||||
co := &config.ContextOptions{}
|
||||
co.Name = "dummy_context"
|
||||
co.Manifest = "dummy_manifest"
|
||||
co.AuthInfo = "dummy_user"
|
||||
co.CurrentContext = false
|
||||
co.Namespace = "dummy_namespace"
|
||||
co.EncryptionConfig = "dummy_encryption_config"
|
||||
|
||||
return co
|
||||
}
|
||||
|
||||
// DummyAuthInfoOptions creates AuthInfoOptions config object
|
||||
// for unit testing
|
||||
func DummyAuthInfoOptions() *config.AuthInfoOptions {
|
||||
authinfo := &config.AuthInfoOptions{}
|
||||
authinfo.Username = "dummy_username"
|
||||
authinfo.Password = "dummy_password"
|
||||
authinfo.ClientCertificate = "dummy_certificate"
|
||||
authinfo.ClientKey = "dummy_key"
|
||||
authinfo.Token = "dummy_token"
|
||||
return authinfo
|
||||
}
|
||||
|
||||
// DummyEncryptionConfig creates EncryptionConfigOptions object
|
||||
// for unit testing
|
||||
func DummyEncryptionConfig() *config.EncryptionConfig {
|
||||
@ -275,31 +194,6 @@ func DummyManifestOptions() *config.ManifestOptions {
|
||||
|
||||
const (
|
||||
testConfigYAML = `apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
default: {}
|
||||
clusters:
|
||||
straggler:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
clusterKubeconf: notThere
|
||||
def:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
clusterKubeconf: def_ephemeral
|
||||
target:
|
||||
clusterKubeconf: def_target
|
||||
onlyinkubeconf:
|
||||
clusterType:
|
||||
target:
|
||||
clusterKubeconf: onlyinkubeconf_target
|
||||
wrongonlyinconfig:
|
||||
clusterType: {}
|
||||
wrongonlyinkubeconf:
|
||||
clusterType:
|
||||
target:
|
||||
clusterKubeconf: wrongonlyinkubeconf_target
|
||||
clustertypenil:
|
||||
clusterType: null
|
||||
contexts:
|
||||
def_ephemeral:
|
||||
contextKubeconf: def_ephemeral
|
||||
@ -310,11 +204,7 @@ contexts:
|
||||
encryptionConfigs: {}
|
||||
currentContext: ""
|
||||
kind: Config
|
||||
manifests: {}
|
||||
users:
|
||||
k-admin: {}
|
||||
k-other: {}
|
||||
def-user: {}`
|
||||
manifests: {}`
|
||||
|
||||
//nolint:lll
|
||||
testKubeConfigYAML = `apiVersion: v1
|
||||
|
@ -53,4 +53,3 @@ mkdir -p $HOME/.airship
|
||||
echo "Generate ~/.airship/config and ~/.airship/kubeconfig"
|
||||
envsubst <"${AIRSHIPCTL_WS}/tools/deployment/templates/airshipconfig_template" > ~/.airship/config
|
||||
envsubst <"${AIRSHIPCTL_WS}/tools/deployment/templates/kubeconfig_template" > ~/.airship/kubeconfig
|
||||
|
||||
|
@ -1,19 +1,4 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
dummy_bootstrap_config:
|
||||
container:
|
||||
volume: ${AIRSHIP_CONFIG_ISO_GEN_TARGET_PATH}:/config
|
||||
image: ${AIRSHIP_CONFIG_ISO_BUILDER_DOCKER_IMAGE}
|
||||
containerRuntime: docker
|
||||
remoteDirect:
|
||||
remoteType: ${REMOTE_TYPE}
|
||||
insecure: ${REMOTE_INSECURE}
|
||||
useproxy: ${REMOTE_PROXY}
|
||||
isoUrl: http://${AIRSHIP_CONFIG_ISO_SERVE_HOST}:${AIRSHIP_CONFIG_ISO_PORT}/${AIRSHIP_CONFIG_ISO_NAME}
|
||||
builder:
|
||||
userDataFileName: user-data
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
managementConfiguration:
|
||||
dummy_management_config:
|
||||
type: ${REMOTE_TYPE}
|
||||
@ -21,26 +6,15 @@ managementConfiguration:
|
||||
useproxy: ${REMOTE_PROXY}
|
||||
systemActionRetries: ${SYSTEM_ACTION_RETRIES}
|
||||
systemRebootDelay: ${SYSTEM_REBOOT_DELAY}
|
||||
|
||||
clusters:
|
||||
ephemeral-cluster:
|
||||
clusterType:
|
||||
ephemeral:
|
||||
bootstrapInfo: dummy_bootstrap_config
|
||||
clusterKubeconf: ephemeral-cluster_ephemeral
|
||||
managementConfiguration: dummy_management_config
|
||||
target-cluster:
|
||||
clusterType:
|
||||
target:
|
||||
clusterKubeconf: target-cluster_target
|
||||
managementConfiguration: dummy_management_config
|
||||
contexts:
|
||||
ephemeral-cluster:
|
||||
contextKubeconf: ephemeral-context
|
||||
contextKubeconf: ephemeral-cluster_ephemeral
|
||||
manifest: dummy_manifest
|
||||
managementConfiguration: dummy_management_config
|
||||
target-cluster:
|
||||
contextKubeconf: target-context
|
||||
contextKubeconf: target-cluster_target
|
||||
manifest: dummy_manifest
|
||||
managementConfiguration: dummy_management_config
|
||||
currentContext: ephemeral-cluster
|
||||
kind: Config
|
||||
manifests:
|
||||
@ -57,6 +31,3 @@ manifests:
|
||||
metadataPath: manifests/metadata.yaml
|
||||
subPath: ${AIRSHIP_SITE_NAME}
|
||||
targetPath: ${AIRSHIP_CONFIG_MANIFEST_DIRECTORY}
|
||||
users:
|
||||
ephemeral-cluster-admin: {}
|
||||
target-cluster-admin: {}
|
||||
|
@ -54,17 +54,11 @@ function generate_airshipconf {
|
||||
|
||||
cat <<EOL > ${AIRSHIPCONFIG}
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
clusters:
|
||||
${CONTEXT}_${cluster}:
|
||||
clusterType:
|
||||
${cluster}:
|
||||
bootstrapInfo: default
|
||||
clusterKubeconf: ${CONTEXT}_${cluster}
|
||||
managementConfiguration: default
|
||||
contexts:
|
||||
${CONTEXT}_${cluster}:
|
||||
contextKubeconf: ${CONTEXT}_${cluster}
|
||||
manifest: ${CONTEXT}_${cluster}
|
||||
managementConfiguration: default
|
||||
currentContext: ${CONTEXT}_${cluster}
|
||||
kind: Config
|
||||
managementConfiguration:
|
||||
@ -86,8 +80,6 @@ manifests:
|
||||
url: https://opendev.org/airship/treasuremap
|
||||
subPath: ${SITE_ROOT}/${SITE}
|
||||
targetPath: ${MANIFEST_ROOT}
|
||||
users:
|
||||
${CONTEXT}_${cluster}: {}
|
||||
EOL
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user