github.com/MichaelDarr/ahab@v0.0.0-20200528062404-c74c5106e605/internal/config.go (about)

     1  package internal
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  )
     9  
    10  // ConfigFileName holds the name of the config file
    11  const ConfigFileName = "ahab.json"
    12  
    13  // UserConfigFilePath holds the path of the user's config file, relative to their home dir
    14  const UserConfigFilePath = ".config/ahab/config.json"
    15  
    16  // Version holds the build-time ahab version
    17  var Version string
    18  
    19  // Configuration contains docker config fields
    20  type Configuration struct {
    21  	AhabVersion       string            `json:"ahab"`
    22  	BuildContext      string            `json:"buildContext"`
    23  	Command           string            `json:"command"`
    24  	Dockerfile        string            `json:"dockerfile"`
    25  	Entrypoint        string            `json:"entrypoint"`
    26  	Environment       []string          `json:"environment"`
    27  	Hostname          string            `json:"hostname"`
    28  	ImageURI          string            `json:"image"`
    29  	Init              []string          `json:"init"`
    30  	Name              string            `json:"name"`
    31  	Options           []string          `json:"options"`
    32  	Permissions       PermConfiguration `json:"permissions"`
    33  	RestartAfterSetup bool              `json:"restartAfterSetup"`
    34  	ShareDisplay      bool              `json:"shareDisplay"`
    35  	User              string            `json:"user"`
    36  	Volumes           []string          `json:"volumes"`
    37  	Workdir           string            `json:"workdir"`
    38  }
    39  
    40  // UserConfiguration contains global user config fields
    41  type UserConfiguration struct {
    42  	Environment  []string `json:"environment"`
    43  	Options      []string `json:"options"`
    44  	HideCommands bool     `json:"hideCommands"`
    45  	Volumes      []string `json:"volumes"`
    46  }
    47  
    48  // PermConfiguration contains information regarding container user permissions setup
    49  type PermConfiguration struct {
    50  	CmdSet  string   `json:"cmdSet"`
    51  	Disable bool     `json:"disable"`
    52  	Groups  []string `json:"groups"`
    53  }
    54  
    55  // UserConfig finds and parses the user's docker config file
    56  // If the user's config is not found, an empty userConfig is returned
    57  func UserConfig() (userConfig *UserConfiguration, err error) {
    58  	homeDir, err := os.UserHomeDir()
    59  	if err != nil {
    60  		err = fmt.Errorf("Failed to get user home directory: %s", err)
    61  		return
    62  	}
    63  
    64  	configPath := filepath.Join(homeDir, UserConfigFilePath)
    65  	configFile, err := os.Open(configPath)
    66  	if err != nil && os.IsNotExist(err) {
    67  		var blankConfig UserConfiguration
    68  		return &blankConfig, nil
    69  	}
    70  	defer configFile.Close()
    71  
    72  	decoder := json.NewDecoder(configFile)
    73  	if err = decoder.Decode(&userConfig); err != nil {
    74  		err = fmt.Errorf("Failed to parse user config file: %s", err)
    75  	}
    76  	return
    77  }
    78  
    79  // checkConfigVersion returns a non-nil err if the passed version is newer the active dcfg version
    80  func checkConfigVersion(configVersion string) error {
    81  	configVersionOrd, err := versionOrdinal(configVersion)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	selfVersionOrd, err := versionOrdinal(Version)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	if configVersionOrd > selfVersionOrd {
    91  		return fmt.Errorf("Config file requires ahab >= %s (your version: %s)", configVersion, Version)
    92  	}
    93  	return nil
    94  }
    95  
    96  // findConfigPath recursively searches for a config file starting at topDir, ending at fs root
    97  func findConfigPath(topDir string) (configPath string, err error) {
    98  	configTestPath := filepath.Join(topDir, ConfigFileName)
    99  	_, err = os.Stat(configTestPath)
   100  	if err != nil && os.IsNotExist(err) && filepath.Clean(topDir) != "/" {
   101  		configPath, err = findConfigPath(filepath.Join(topDir, ".."))
   102  	} else if err != nil && os.IsNotExist(err) {
   103  		err = fmt.Errorf("No config file '%s' found in current or parent directories", ConfigFileName)
   104  	} else if err != nil {
   105  		err = fmt.Errorf("Failed to find config file '%s': %s", ConfigFileName, err)
   106  	} else {
   107  		configPath = configTestPath
   108  	}
   109  	return
   110  }
   111  
   112  // return a non-nil error if config is invalid
   113  func (config *Configuration) validateConfig() (err error) {
   114  	if config.AhabVersion == "" {
   115  		err = fmt.Errorf("Missing required version field 'ahab'")
   116  	} else if config.ImageURI == "" && config.Dockerfile == "" {
   117  		err = fmt.Errorf("Either 'image' or 'dockerfile' must be present")
   118  	} else if config.ImageURI != "" && config.Dockerfile != "" {
   119  		err = fmt.Errorf("'image' and `dockerfile' cannot both be present")
   120  	}
   121  	return
   122  }