mirror of https://github.com/rancher/cli.git
168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"k8s.io/client-go/tools/clientcmd/api"
|
|
)
|
|
|
|
var ErrNoConfigurationFound = errors.New("no configuration found, run `login`")
|
|
|
|
// Config holds the main config for the user
|
|
type Config struct {
|
|
Servers map[string]*ServerConfig
|
|
//Path to the config file
|
|
Path string `json:"path,omitempty"`
|
|
// CurrentServer the user has in focus
|
|
CurrentServer string
|
|
}
|
|
|
|
// ServerConfig holds the config for each server the user has setup
|
|
type ServerConfig struct {
|
|
AccessKey string `json:"accessKey"`
|
|
SecretKey string `json:"secretKey"`
|
|
TokenKey string `json:"tokenKey"`
|
|
URL string `json:"url"`
|
|
Project string `json:"project"`
|
|
CACerts string `json:"cacert"`
|
|
KubeCredentials map[string]*ExecCredential `json:"kubeCredentials"`
|
|
KubeConfigs map[string]*api.Config `json:"kubeConfigs"`
|
|
ProxyURL string `json:"proxyUrl"`
|
|
HTTPTimeoutSeconds int `json:"httpTimeoutSeconds"`
|
|
}
|
|
|
|
func (c *ServerConfig) GetHTTPTimeout() time.Duration {
|
|
return time.Duration(c.HTTPTimeoutSeconds) * time.Second
|
|
}
|
|
|
|
// LoadFromPath attempts to load a config from the given file path. If the file
|
|
// doesn't exist, an empty config is returned.
|
|
func LoadFromPath(path string) (Config, error) {
|
|
cf := Config{
|
|
Path: path,
|
|
Servers: make(map[string]*ServerConfig),
|
|
}
|
|
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
// it's okay if the file is empty, we still return a valid config
|
|
if os.IsNotExist(err) {
|
|
return cf, nil
|
|
}
|
|
|
|
return cf, err
|
|
}
|
|
|
|
if err := json.Unmarshal(content, &cf); err != nil {
|
|
return cf, fmt.Errorf("unmarshaling %s: %w", path, err)
|
|
}
|
|
cf.Path = path
|
|
|
|
return cf, nil
|
|
}
|
|
|
|
// GetFilePermissionWarnings returns the following warnings based on the file permission:
|
|
// - one warning if the file is group-readable
|
|
// - one warning if the file is world-readable
|
|
// We want this because configuration may have sensitive information (eg: creds).
|
|
// A nil error is returned if the file doesn't exist.
|
|
func GetFilePermissionWarnings(path string) ([]string, error) {
|
|
// Permission bits on Windows are not representative
|
|
// of the actual ACLs set for a given file. As the owner
|
|
// bit is always used for all three bits on Windows, this check
|
|
// will always fail, even if the file has restricted access to admins only.
|
|
if runtime.GOOS == "windows" {
|
|
return nil, nil
|
|
}
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return []string{}, nil
|
|
}
|
|
return []string{}, fmt.Errorf("get file info: %w", err)
|
|
}
|
|
|
|
var warnings []string
|
|
if info.Mode()&0040 > 0 {
|
|
warnings = append(warnings, fmt.Sprintf("Rancher configuration file %s is group-readable. This is insecure.", path))
|
|
}
|
|
if info.Mode()&0004 > 0 {
|
|
warnings = append(warnings, fmt.Sprintf("Rancher configuration file %s is world-readable. This is insecure.", path))
|
|
}
|
|
return warnings, nil
|
|
}
|
|
|
|
func (c Config) Write() error {
|
|
err := os.MkdirAll(filepath.Dir(c.Path), 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.Infof("Saving config to %s", c.Path)
|
|
p := c.Path
|
|
c.Path = ""
|
|
output, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer output.Close()
|
|
|
|
return json.NewEncoder(output).Encode(c)
|
|
}
|
|
|
|
func (c Config) FocusedServer() (*ServerConfig, error) {
|
|
currentServer, found := c.Servers[c.CurrentServer]
|
|
if !found || currentServer == nil {
|
|
return nil, ErrNoConfigurationFound
|
|
}
|
|
return currentServer, nil
|
|
}
|
|
|
|
func (c ServerConfig) FocusedCluster() string {
|
|
cluster, _, ok := strings.Cut(c.Project, ":")
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return cluster
|
|
}
|
|
|
|
func (c ServerConfig) FocusedProject() string {
|
|
return c.Project
|
|
}
|
|
|
|
func (c ServerConfig) KubeToken(key string) *ExecCredential {
|
|
return c.KubeCredentials[key]
|
|
}
|
|
|
|
func (c ServerConfig) EnvironmentURL() (string, error) {
|
|
url, err := baseURL(c.URL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return url, nil
|
|
}
|
|
|
|
func baseURL(fullURL string) (string, error) {
|
|
idx := strings.LastIndex(fullURL, "/v3")
|
|
if idx == -1 {
|
|
u, err := url.Parse(fullURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
newURL := url.URL{
|
|
Scheme: u.Scheme,
|
|
Host: u.Host,
|
|
}
|
|
return newURL.String(), nil
|
|
}
|
|
return fullURL[:idx], nil
|
|
}
|