Merge "Refactor management of config file paths"
This commit is contained in:
commit
6e8ca5b010
@ -29,21 +29,20 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/util"
|
||||
)
|
||||
|
||||
// Called from root to Load the initial configuration
|
||||
func (c *Config) LoadConfig(configFileArg string, kPathOptions *clientcmd.PathOptions) error {
|
||||
err := c.loadFromAirConfig(configFileArg)
|
||||
// LoadConfig populates the Config object using the files found at
|
||||
// airshipConfigPath and kubeConfigPath
|
||||
func (c *Config) LoadConfig(airshipConfigPath, kubeConfigPath string) error {
|
||||
err := c.loadFromAirConfig(airshipConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load or initialize the kubeconfig object from a file
|
||||
err = c.loadKubeConfig(kPathOptions)
|
||||
err = c.loadKubeConfig(kubeConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -52,36 +51,45 @@ func (c *Config) LoadConfig(configFileArg string, kPathOptions *clientcmd.PathOp
|
||||
return c.reconcileConfig()
|
||||
}
|
||||
|
||||
func (c *Config) loadFromAirConfig(configFileArg string) error {
|
||||
// If it exists, Read the ConfigFile data
|
||||
// Only care about the errors here, because there is a file
|
||||
// And essentially I cannot use its data.
|
||||
// airshipctl probable should stop
|
||||
if configFileArg == "" {
|
||||
// loadFromAirConfig populates the Config from the file found at airshipConfigPath.
|
||||
// If there is no file at airshipConfigPath, this function does nothing.
|
||||
// An error is returned if:
|
||||
// * airshipConfigPath is the empty string
|
||||
// * the file at airshipConfigPath is inaccessible
|
||||
// * the file at airshipConfigPath cannot be marshaled into Config
|
||||
func (c *Config) loadFromAirConfig(airshipConfigPath string) error {
|
||||
if airshipConfigPath == "" {
|
||||
return errors.New("Configuration file location was not provided.")
|
||||
}
|
||||
|
||||
// Remember where I loaded the Config from
|
||||
c.loadedConfigPath = configFileArg
|
||||
// If I have a file to read, load from it
|
||||
c.loadedConfigPath = airshipConfigPath
|
||||
|
||||
if _, err := os.Stat(configFileArg); os.IsNotExist(err) {
|
||||
// If I can read from the file, load from it
|
||||
if _, err := os.Stat(airshipConfigPath); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return util.ReadYAMLFile(configFileArg, c)
|
||||
}
|
||||
|
||||
func (c *Config) loadKubeConfig(kPathOptions *clientcmd.PathOptions) error {
|
||||
// Will need this for Persisting the changes
|
||||
c.loadedPathOptions = kPathOptions
|
||||
// Now at this point what I load might not reflect the associated kubeconfig yet
|
||||
kConfig, err := kPathOptions.GetStartingConfig()
|
||||
if err != nil {
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
// Store the kubeconfig object into an airship managed kubeconfig object
|
||||
c.kubeConfig = kConfig
|
||||
|
||||
return nil
|
||||
return util.ReadYAMLFile(airshipConfigPath, c)
|
||||
}
|
||||
|
||||
func (c *Config) loadKubeConfig(kubeConfigPath string) error {
|
||||
// Will need this for persisting the changes
|
||||
c.kubeConfigPath = kubeConfigPath
|
||||
|
||||
// If I can read from the file, load from it
|
||||
var err error
|
||||
if _, err = os.Stat(kubeConfigPath); os.IsNotExist(err) {
|
||||
c.kubeConfig = clientcmdapi.NewConfig()
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.kubeConfig, err = clientcmd.LoadFromFile(kubeConfigPath)
|
||||
return err
|
||||
}
|
||||
|
||||
// reconcileConfig serves two functions:
|
||||
@ -198,6 +206,7 @@ func (c *Config) rmConfigClusterStragglers(persistIt bool) bool {
|
||||
}
|
||||
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
|
||||
@ -254,7 +263,7 @@ func (c *Config) reconcileAuthInfos() {
|
||||
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 kubeconfiug CC
|
||||
// - 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
|
||||
|
||||
@ -326,20 +335,17 @@ func (c *Config) EnsureComplete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This function is called to update the configuration in the file defined by the
|
||||
// ConfigFile name
|
||||
// It will completely overwrite the existing file,
|
||||
// If the file specified by ConfigFile exists ts updates with the contents of the Config object
|
||||
// If the file specified by ConfigFile does not exist it will create a new file.
|
||||
// PersistConfig updates the airshipctl config and kubeconfig files to match
|
||||
// the current Config and KubeConfig objects.
|
||||
// If either file did not previously exist, the file will be created.
|
||||
// Otherwise, the file will be overwritten
|
||||
func (c *Config) PersistConfig() error {
|
||||
// Dont care if the file exists or not, will create if needed
|
||||
// We are 100% overwriting the existing file
|
||||
configyaml, err := c.ToYaml()
|
||||
airshipConfigYaml, err := c.ToYaml()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteFile doesn't create the directory , create it if needed
|
||||
// WriteFile doesn't create the directory, create it if needed
|
||||
configDir := filepath.Dir(c.loadedConfigPath)
|
||||
err = os.MkdirAll(configDir, 0755)
|
||||
if err != nil {
|
||||
@ -347,19 +353,13 @@ func (c *Config) PersistConfig() error {
|
||||
}
|
||||
|
||||
// Write the Airship Config file
|
||||
err = ioutil.WriteFile(c.loadedConfigPath, configyaml, 0644)
|
||||
err = ioutil.WriteFile(c.loadedConfigPath, airshipConfigYaml, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME(howell): if this fails, then the results from the previous
|
||||
// actions will persist, meaning that we might have overwritten our
|
||||
// airshipconfig without updating our kubeconfig. A possible solution
|
||||
// is to generate brand new config files and then write them at the
|
||||
// end. That could still fail, but should be more robust
|
||||
|
||||
// Persist the kubeconfig file referenced
|
||||
if err := clientcmd.ModifyConfig(c.loadedPathOptions, *c.kubeConfig, true); err != nil {
|
||||
if err := clientcmd.WriteToFile(*c.kubeConfig, c.kubeConfigPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -386,14 +386,15 @@ func (c *Config) SetLoadedConfigPath(lcp string) {
|
||||
c.loadedConfigPath = lcp
|
||||
}
|
||||
|
||||
func (c *Config) LoadedPathOptions() *clientcmd.PathOptions {
|
||||
return c.loadedPathOptions
|
||||
}
|
||||
func (c *Config) SetLoadedPathOptions(po *clientcmd.PathOptions) {
|
||||
c.loadedPathOptions = po
|
||||
func (c *Config) KubeConfigPath() string {
|
||||
return c.kubeConfigPath
|
||||
}
|
||||
|
||||
func (c *Config) KubeConfig() *kubeconfig.Config {
|
||||
func (c *Config) SetKubeConfigPath(kubeConfigPath string) {
|
||||
c.kubeConfigPath = kubeConfigPath
|
||||
}
|
||||
|
||||
func (c *Config) KubeConfig() *clientcmdapi.Config {
|
||||
return c.kubeConfig
|
||||
}
|
||||
|
||||
@ -441,7 +442,7 @@ func (c *Config) AddCluster(theCluster *ClusterOptions) (*Cluster, error) {
|
||||
nCluster := NewCluster()
|
||||
c.Clusters[theCluster.Name].ClusterTypes[theCluster.ClusterType] = nCluster
|
||||
// Create a new Kubeconfig Cluster object as well
|
||||
kcluster := kubeconfig.NewCluster()
|
||||
kcluster := clientcmdapi.NewCluster()
|
||||
clusterName := NewClusterComplexName()
|
||||
clusterName.WithType(theCluster.Name, theCluster.ClusterType)
|
||||
nCluster.NameInKubeconf = clusterName.Name()
|
||||
@ -541,7 +542,7 @@ func (c *Config) AddContext(theContext *ContextOptions) *Context {
|
||||
nContext := NewContext()
|
||||
c.Contexts[theContext.Name] = nContext
|
||||
// Create a new Kubeconfig Context object as well
|
||||
kContext := kubeconfig.NewContext()
|
||||
kContext := clientcmdapi.NewContext()
|
||||
nContext.NameInKubeconf = theContext.Name
|
||||
contextName := NewClusterComplexName()
|
||||
contextName.WithType(theContext.Name, theContext.ClusterType)
|
||||
@ -645,7 +646,7 @@ func (c *Config) AddAuthInfo(theAuthInfo *AuthInfoOptions) *AuthInfo {
|
||||
nAuthInfo := NewAuthInfo()
|
||||
c.AuthInfos[theAuthInfo.Name] = nAuthInfo
|
||||
// Create a new Kubeconfig AuthInfo object as well
|
||||
kAuthInfo := kubeconfig.NewAuthInfo()
|
||||
kAuthInfo := clientcmdapi.NewAuthInfo()
|
||||
nAuthInfo.SetKubeAuthInfo(kAuthInfo)
|
||||
c.KubeConfig().AuthInfos[theAuthInfo.Name] = kAuthInfo
|
||||
|
||||
@ -739,10 +740,10 @@ func (c *Cluster) PrettyString() string {
|
||||
clusterName.ClusterName(), clusterName.ClusterType(), c)
|
||||
}
|
||||
|
||||
func (c *Cluster) KubeCluster() *kubeconfig.Cluster {
|
||||
func (c *Cluster) KubeCluster() *clientcmdapi.Cluster {
|
||||
return c.kCluster
|
||||
}
|
||||
func (c *Cluster) SetKubeCluster(kc *kubeconfig.Cluster) {
|
||||
func (c *Cluster) SetKubeCluster(kc *clientcmdapi.Cluster) {
|
||||
c.kCluster = kc
|
||||
}
|
||||
|
||||
@ -777,11 +778,11 @@ func (c *Context) PrettyString() string {
|
||||
clusterName.ClusterName(), c.String())
|
||||
}
|
||||
|
||||
func (c *Context) KubeContext() *kubeconfig.Context {
|
||||
func (c *Context) KubeContext() *clientcmdapi.Context {
|
||||
return c.kContext
|
||||
}
|
||||
|
||||
func (c *Context) SetKubeContext(kc *kubeconfig.Context) {
|
||||
func (c *Context) SetKubeContext(kc *clientcmdapi.Context) {
|
||||
c.kContext = kc
|
||||
}
|
||||
|
||||
@ -808,10 +809,10 @@ func (c *AuthInfo) String() string {
|
||||
return string(kyaml)
|
||||
}
|
||||
|
||||
func (c *AuthInfo) KubeAuthInfo() *kubeconfig.AuthInfo {
|
||||
func (c *AuthInfo) KubeAuthInfo() *clientcmdapi.AuthInfo {
|
||||
return c.kAuthInfo
|
||||
}
|
||||
func (c *AuthInfo) SetKubeAuthInfo(kc *kubeconfig.AuthInfo) {
|
||||
func (c *AuthInfo) SetKubeAuthInfo(kc *clientcmdapi.AuthInfo) {
|
||||
c.kAuthInfo = kc
|
||||
}
|
||||
|
||||
@ -979,7 +980,7 @@ PLACEHOLDER UNTIL I IDENTIFY if CLIENTADM
|
||||
HAS SOMETHING LIKE THIS
|
||||
*/
|
||||
|
||||
func KClusterString(kCluster *kubeconfig.Cluster) string {
|
||||
func KClusterString(kCluster *clientcmdapi.Cluster) string {
|
||||
yamlData, err := yaml.Marshal(&kCluster)
|
||||
if err != nil {
|
||||
return ""
|
||||
@ -987,7 +988,8 @@ func KClusterString(kCluster *kubeconfig.Cluster) string {
|
||||
|
||||
return string(yamlData)
|
||||
}
|
||||
func KContextString(kContext *kubeconfig.Context) string {
|
||||
|
||||
func KContextString(kContext *clientcmdapi.Context) string {
|
||||
yamlData, err := yaml.Marshal(&kContext)
|
||||
if err != nil {
|
||||
return ""
|
||||
@ -995,7 +997,8 @@ func KContextString(kContext *kubeconfig.Context) string {
|
||||
|
||||
return string(yamlData)
|
||||
}
|
||||
func KAuthInfoString(kAuthInfo *kubeconfig.AuthInfo) string {
|
||||
|
||||
func KAuthInfoString(kAuthInfo *clientcmdapi.AuthInfo) string {
|
||||
yamlData, err := yaml.Marshal(&kAuthInfo)
|
||||
if err != nil {
|
||||
return ""
|
||||
|
@ -26,7 +26,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
@ -224,10 +223,11 @@ func TestPersistConfig(t *testing.T) {
|
||||
config := InitConfig(t)
|
||||
|
||||
err := config.PersistConfig()
|
||||
assert.NoErrorf(t, err, "Unable to persist configuration expected at %v", config.LoadedConfigPath())
|
||||
require.NoError(t, err)
|
||||
|
||||
kpo := config.LoadedPathOptions()
|
||||
assert.NotNil(t, kpo)
|
||||
// Check that the files were created
|
||||
assert.FileExists(t, config.LoadedConfigPath())
|
||||
assert.FileExists(t, config.KubeConfigPath())
|
||||
}
|
||||
|
||||
func TestEnsureComplete(t *testing.T) {
|
||||
@ -347,11 +347,10 @@ func TestPurge(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
airConfigFile := filepath.Join(tempDir, AirshipConfig)
|
||||
kConfigFile := filepath.Join(tempDir, AirshipKubeConfig)
|
||||
config.SetLoadedConfigPath(airConfigFile)
|
||||
kubePathOptions := clientcmd.NewDefaultPathOptions()
|
||||
kubePathOptions.GlobalFile = kConfigFile
|
||||
config.SetLoadedPathOptions(kubePathOptions)
|
||||
|
||||
kConfigFile := filepath.Join(tempDir, AirshipKubeConfig)
|
||||
config.kubeConfigPath = kConfigFile
|
||||
|
||||
// Store it
|
||||
err = config.PersistConfig()
|
||||
|
@ -11,19 +11,22 @@ const (
|
||||
AirshipClusterDefaultType = Target
|
||||
)
|
||||
|
||||
//Sorted
|
||||
// Sorted
|
||||
var AllClusterTypes = [2]string{Ephemeral, Target}
|
||||
|
||||
// Constants defining default values
|
||||
const (
|
||||
AirshipConfigEnv = "airshipconf"
|
||||
AirshipConfig = "config"
|
||||
AirshipConfigDir = ".airship"
|
||||
AirshipConfigKind = "Config"
|
||||
AirshipConfigVersion = "v1alpha1"
|
||||
AirshipConfigGroup = "airshipit.org"
|
||||
AirshipConfigVersion = "v1alpha1"
|
||||
AirshipConfigApiVersion = AirshipConfigGroup + "/" + AirshipConfigVersion
|
||||
AirshipKubeConfig = "kubeconfig"
|
||||
AirshipConfigKind = "Config"
|
||||
|
||||
AirshipConfigDir = ".airship"
|
||||
AirshipConfig = "config"
|
||||
AirshipKubeConfig = "kubeconfig"
|
||||
|
||||
AirshipConfigEnv = "AIRSHIPCONFIG"
|
||||
AirshipKubeConfigEnv = "AIRSHIP_KUBECONFIG"
|
||||
)
|
||||
|
||||
// Constants defining CLI flags
|
||||
@ -37,7 +40,7 @@ const (
|
||||
FlagClusterType = "cluster-type"
|
||||
FlagContext = "context"
|
||||
FlagCurrentContext = "current-context"
|
||||
FlagConfigFilePath = AirshipConfigEnv
|
||||
FlagConfigFilePath = "airshipconf"
|
||||
FlagEmbedCerts = "embed-certs"
|
||||
FlagImpersonate = "as"
|
||||
FlagImpersonateGroup = "as-group"
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -145,9 +144,7 @@ func InitConfig(t *testing.T) *Config {
|
||||
|
||||
conf := NewConfig()
|
||||
|
||||
kubePathOptions := clientcmd.NewDefaultPathOptions()
|
||||
kubePathOptions.GlobalFile = kubeConfigPath
|
||||
err = conf.LoadConfig(configPath, kubePathOptions)
|
||||
err = conf.LoadConfig(configPath, kubeConfigPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
return conf
|
||||
|
@ -19,7 +19,6 @@ package config
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
@ -57,15 +56,15 @@ type Config struct {
|
||||
// Such as Bootstrap, Workflows, Document, etc
|
||||
ModulesConfig *Modules `json:"modules-config"`
|
||||
|
||||
// Private LoadedConfigPath is the full path to the the location of the config file
|
||||
// from which these config was loaded
|
||||
// loadedConfigPath is the full path to the the location of the config
|
||||
// file from which this config was loaded
|
||||
// +not persisted in file
|
||||
loadedConfigPath string
|
||||
|
||||
// Private loadedPathOptions is the full path to the the location of the kubeconfig file
|
||||
// associated with this airship config instance
|
||||
// kubeConfigPath is the full path to the the location of the
|
||||
// kubeconfig file associated with this airship config instance
|
||||
// +not persisted in file
|
||||
loadedPathOptions *clientcmd.PathOptions
|
||||
kubeConfigPath string
|
||||
|
||||
// Private instance of Kube Config content as an object
|
||||
kubeConfig *kubeconfig.Config
|
||||
|
@ -3,7 +3,6 @@ package environment
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@ -64,67 +63,64 @@ func (a *AirshipCTLSettings) SetKubeConfigPath(kcp string) {
|
||||
func (a *AirshipCTLSettings) InitConfig() {
|
||||
a.SetConfig(config.NewConfig())
|
||||
|
||||
a.setAirshipConfigPath()
|
||||
a.initAirshipConfigPath()
|
||||
a.initKubeConfigPath()
|
||||
|
||||
//Pass the airshipConfigPath and kubeConfig object
|
||||
err := a.Config().LoadConfig(a.AirshipConfigPath(), a.setKubePathOptions())
|
||||
err := a.Config().LoadConfig(a.AirshipConfigPath(), a.KubeConfigPath())
|
||||
if err != nil {
|
||||
// Should stop airshipctl
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AirshipCTLSettings) setAirshipConfigPath() {
|
||||
// (1) If the airshipConfigPath was received as an argument its already set
|
||||
if a.airshipConfigPath == "" {
|
||||
// (2) If not , we can check if we got the Path via ENVIRONMENT variable,
|
||||
// set the appropriate fields
|
||||
a.setAirshipConfigPathFromEnv()
|
||||
func (a *AirshipCTLSettings) initAirshipConfigPath() {
|
||||
// The airshipConfigPath may already have been received as a command line argument
|
||||
if a.airshipConfigPath != "" {
|
||||
return
|
||||
}
|
||||
// (3) Check if the a.airshipConfigPath is empty still at this point , use the defaults
|
||||
acp, home := a.replaceHomePlaceholder(a.airshipConfigPath)
|
||||
a.airshipConfigPath = acp
|
||||
if a.airshipConfigPath == "" {
|
||||
a.airshipConfigPath = filepath.Join(home, config.AirshipConfigDir, config.AirshipConfig)
|
||||
}
|
||||
}
|
||||
|
||||
// setAirshipConfigPathFromEnv Get AIRSHIP CONFIG from an environment variable if set
|
||||
func (a *AirshipCTLSettings) setAirshipConfigPathFromEnv() {
|
||||
// Check if AIRSHIPCONF env variable was set
|
||||
// I have the path and name for the airship config file
|
||||
// Otherwise, we can check if we got the path via ENVIRONMENT variable
|
||||
a.airshipConfigPath = os.Getenv(config.AirshipConfigEnv)
|
||||
}
|
||||
|
||||
func (a *AirshipCTLSettings) setKubePathOptions() *clientcmd.PathOptions {
|
||||
// USe default expectations for Kubeconfig
|
||||
kubePathOptions := clientcmd.NewDefaultPathOptions()
|
||||
// No need to check the Environment , since we are relying on the kubeconfig defaults
|
||||
// If we did not get an explicit kubeconfig definition on airshipctl
|
||||
// as far as airshipctl is concerned will use the default expectations for the kubeconfig
|
||||
// file location . This avoids messing up someones kubeconfig if they didnt explicitly want
|
||||
// airshipctl to use it.
|
||||
kcp, home := a.replaceHomePlaceholder(a.kubeConfigPath)
|
||||
a.kubeConfigPath = kcp
|
||||
if a.kubeConfigPath == "" {
|
||||
a.kubeConfigPath = filepath.Join(home, config.AirshipConfigDir, config.AirshipKubeConfig)
|
||||
if a.airshipConfigPath != "" {
|
||||
return
|
||||
}
|
||||
// We will always rely on tha airshipctl cli args or default for where to find kubeconfig
|
||||
kubePathOptions.GlobalFile = a.kubeConfigPath
|
||||
kubePathOptions.GlobalFileSubpath = a.kubeConfigPath
|
||||
|
||||
return kubePathOptions
|
||||
// Otherwise, we'll try putting it in the home directory
|
||||
homeDir := userHomeDir()
|
||||
a.airshipConfigPath = filepath.Join(homeDir, config.AirshipConfigDir, config.AirshipConfig)
|
||||
}
|
||||
|
||||
func (a *AirshipCTLSettings) replaceHomePlaceholder(configPath string) (string, string) {
|
||||
home, err := os.UserHomeDir()
|
||||
func (a *AirshipCTLSettings) initKubeConfigPath() {
|
||||
// NOTE(howell): This function will set the kubeConfigPath to the
|
||||
// default location under the airship directory unless the user
|
||||
// *explicitly* specifies a different location, either by setting the
|
||||
// ENVIRONMENT variable or by passing a command line argument.
|
||||
// This avoids messing up the user's kubeconfig if they didn't
|
||||
// explicitly want airshipctl to use it.
|
||||
|
||||
// The kubeConfigPath may already have been received as a command line argument
|
||||
if a.kubeConfigPath != "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we can check if we got the path via ENVIRONMENT variable
|
||||
a.kubeConfigPath = os.Getenv(config.AirshipKubeConfigEnv)
|
||||
if a.kubeConfigPath != "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we'll try putting it in the home directory
|
||||
homeDir := userHomeDir()
|
||||
a.kubeConfigPath = filepath.Join(homeDir, config.AirshipConfigDir, config.AirshipKubeConfig)
|
||||
}
|
||||
|
||||
// userHomeDir is a utility function that wraps os.UserHomeDir and returns no
|
||||
// errors. If the user has no home directory, the returned value will be the
|
||||
// empty string
|
||||
func userHomeDir() string {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
// Use defaults under current directory
|
||||
home = ""
|
||||
homeDir = ""
|
||||
}
|
||||
if configPath == "" {
|
||||
return configPath, home
|
||||
}
|
||||
|
||||
return strings.Replace(configPath, HomePlaceholder, home, 1), home
|
||||
return homeDir
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package environment
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -36,25 +37,107 @@ func TestInitFlags(t *testing.T) {
|
||||
assert.True(t, testCmd.HasPersistentFlags())
|
||||
}
|
||||
|
||||
func TestSpecifyAirConfigFromEnv(t *testing.T) {
|
||||
fakeConfig := "FakeConfigPath"
|
||||
err := os.Setenv(config.AirshipConfigEnv, fakeConfig)
|
||||
func TestInitConfig(t *testing.T) {
|
||||
t.Run("DefaultToHomeDirectory", func(subTest *testing.T) {
|
||||
// Set up a fake $HOME directory
|
||||
testDir := makeTestDir(t)
|
||||
defer deleteTestDir(t, testDir)
|
||||
defer setHome(testDir)()
|
||||
|
||||
var testSettings AirshipCTLSettings
|
||||
expectedAirshipConfig := filepath.Join(testDir, config.AirshipConfigDir, config.AirshipConfig)
|
||||
expectedKubeConfig := filepath.Join(testDir, config.AirshipConfigDir, config.AirshipKubeConfig)
|
||||
|
||||
testSettings.InitConfig()
|
||||
assert.Equal(t, expectedAirshipConfig, testSettings.AirshipConfigPath())
|
||||
assert.Equal(t, expectedKubeConfig, testSettings.KubeConfigPath())
|
||||
})
|
||||
|
||||
t.Run("PreferEnvToDefault", func(subTest *testing.T) {
|
||||
// Set up a fake $HOME directory
|
||||
testDir := makeTestDir(t)
|
||||
defer deleteTestDir(t, testDir)
|
||||
defer setHome(testDir)()
|
||||
|
||||
var testSettings AirshipCTLSettings
|
||||
expectedAirshipConfig := filepath.Join(testDir, "airshipEnv")
|
||||
expectedKubeConfig := filepath.Join(testDir, "kubeEnv")
|
||||
|
||||
os.Setenv(config.AirshipConfigEnv, expectedAirshipConfig)
|
||||
os.Setenv(config.AirshipKubeConfigEnv, expectedKubeConfig)
|
||||
defer os.Unsetenv(config.AirshipConfigEnv)
|
||||
defer os.Unsetenv(config.AirshipKubeConfigEnv)
|
||||
|
||||
testSettings.InitConfig()
|
||||
assert.Equal(t, expectedAirshipConfig, testSettings.AirshipConfigPath())
|
||||
assert.Equal(t, expectedKubeConfig, testSettings.KubeConfigPath())
|
||||
})
|
||||
|
||||
t.Run("PreferCmdLineArgToDefault", func(subTest *testing.T) {
|
||||
// Set up a fake $HOME directory
|
||||
testDir := makeTestDir(t)
|
||||
defer deleteTestDir(t, testDir)
|
||||
defer setHome(testDir)()
|
||||
|
||||
var testSettings AirshipCTLSettings
|
||||
expectedAirshipConfig := filepath.Join(testDir, "airshipCmdLine")
|
||||
expectedKubeConfig := filepath.Join(testDir, "kubeCmdLine")
|
||||
|
||||
testSettings.SetAirshipConfigPath(expectedAirshipConfig)
|
||||
testSettings.SetKubeConfigPath(expectedKubeConfig)
|
||||
|
||||
// InitConfig should not change any values
|
||||
testSettings.InitConfig()
|
||||
assert.Equal(t, expectedAirshipConfig, testSettings.AirshipConfigPath())
|
||||
assert.Equal(t, expectedKubeConfig, testSettings.KubeConfigPath())
|
||||
})
|
||||
|
||||
t.Run("PreferCmdLineArgToEnv", func(subTest *testing.T) {
|
||||
// Set up a fake $HOME directory
|
||||
testDir := makeTestDir(t)
|
||||
defer deleteTestDir(t, testDir)
|
||||
defer setHome(testDir)()
|
||||
|
||||
var testSettings AirshipCTLSettings
|
||||
expectedAirshipConfig := filepath.Join(testDir, "airshipCmdLine")
|
||||
expectedKubeConfig := filepath.Join(testDir, "kubeCmdLine")
|
||||
|
||||
// set up "decoy" environment variables. These should be
|
||||
// ignored, since we're simulating passing in command line
|
||||
// arguments
|
||||
wrongAirshipConfig := filepath.Join(testDir, "wrongAirshipConfig")
|
||||
wrongKubeConfig := filepath.Join(testDir, "wrongKubeConfig")
|
||||
os.Setenv(config.AirshipConfigEnv, wrongAirshipConfig)
|
||||
os.Setenv(config.AirshipKubeConfigEnv, wrongKubeConfig)
|
||||
defer os.Unsetenv(config.AirshipConfigEnv)
|
||||
defer os.Unsetenv(config.AirshipKubeConfigEnv)
|
||||
|
||||
testSettings.SetAirshipConfigPath(expectedAirshipConfig)
|
||||
testSettings.SetKubeConfigPath(expectedKubeConfig)
|
||||
|
||||
testSettings.InitConfig()
|
||||
assert.Equal(t, expectedAirshipConfig, testSettings.AirshipConfigPath())
|
||||
assert.Equal(t, expectedKubeConfig, testSettings.KubeConfigPath())
|
||||
})
|
||||
}
|
||||
|
||||
func makeTestDir(t *testing.T) string {
|
||||
testDir, err := ioutil.TempDir("", "airship-test")
|
||||
require.NoError(t, err)
|
||||
|
||||
settings := &AirshipCTLSettings{}
|
||||
settings.InitConfig()
|
||||
|
||||
assert.EqualValues(t, fakeConfig, settings.AirshipConfigPath())
|
||||
return testDir
|
||||
}
|
||||
|
||||
func TestGetSetPaths(t *testing.T) {
|
||||
settings := &AirshipCTLSettings{}
|
||||
settings.InitConfig()
|
||||
airConfigFile := filepath.Join(config.AirshipConfigDir, config.AirshipConfig)
|
||||
kConfigFile := filepath.Join(config.AirshipConfigDir, config.AirshipKubeConfig)
|
||||
settings.SetAirshipConfigPath(airConfigFile)
|
||||
assert.EqualValues(t, airConfigFile, settings.AirshipConfigPath())
|
||||
|
||||
settings.SetKubeConfigPath(kConfigFile)
|
||||
assert.EqualValues(t, kConfigFile, settings.KubeConfigPath())
|
||||
func deleteTestDir(t *testing.T, path string) {
|
||||
err := os.Remove(path)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// setHome sets the HOME environment variable to `path`, and returns a function
|
||||
// that can be used to reset HOME to its original value
|
||||
func setHome(path string) (resetHome func()) {
|
||||
oldHome := os.Getenv("HOME")
|
||||
os.Setenv("HOME", path)
|
||||
return func() {
|
||||
os.Setenv("HOME", oldHome)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user