Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/root: Add support for configuration files #828

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions data/config/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
install_data(
'toolbox.conf',
install_dir: join_paths(get_option('sysconfdir'), 'containers'),
)
17 changes: 17 additions & 0 deletions data/config/toolbox.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[general]
debarshiray marked this conversation as resolved.
Show resolved Hide resolved
# Create a toolbox container for a different operating system distro than the
# host. Cannot be used with 'image'.
## distro = "fedora"

# Create a toolbox container for a different operating system release than the
# host. Cannot be used with 'image'.
## release = "33"

# Change the name of the image used to create the toolbox container. This is
# useful for creating containers from custom-built images. Cannot be used with
# 'distro' or 'release'.
#
# If the name does not contain a registry, the local image storage will be
# consulted, and if it's not present there then it will be pulled from a
# suitable remote registry.
## image = "registry.fedoraproject.org/fedora-toolbox:33"
1 change: 1 addition & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
subdir('config')
subdir('tmpfiles.d')
7 changes: 2 additions & 5 deletions src/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func createContainer(container, image, release string, showCommandToEnter bool)
panic("release not specified")
}

enterCommand := getEnterCommand(container, release)
enterCommand := getEnterCommand(container)

logrus.Debugf("Checking if container %s already exists", container)

Expand Down Expand Up @@ -503,15 +503,12 @@ func getDBusSystemSocket() (string, error) {
return pathEvaled, nil
}

func getEnterCommand(container, release string) string {
func getEnterCommand(container string) string {
var enterCommand string
containerNamePrefixDefaultWithRelease := utils.ContainerNamePrefixDefault + "-" + release

switch container {
case utils.ContainerNameDefault:
enterCommand = fmt.Sprintf("%s enter", executableBase)
case containerNamePrefixDefaultWithRelease:
enterCommand = fmt.Sprintf("%s enter --release %s", executableBase, release)
default:
enterCommand = fmt.Sprintf("%s enter %s", executableBase, container)
}
Expand Down
4 changes: 4 additions & 0 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ func preRun(cmd *cobra.Command, args []string) error {
return err
}

if err := utils.SetUpConfiguration(); err != nil {
return err
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/mattn/go-isatty v0.0.8
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.3.2
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
Expand Down
10 changes: 10 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,39 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -61,9 +69,11 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
113 changes: 97 additions & 16 deletions src/pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/docker/go-units"
"github.com/godbus/dbus/v5"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"golang.org/x/sys/unix"
)

Expand All @@ -61,6 +62,8 @@ const (
)

var (
containerNamePrefixDefault = "fedora-toolbox"

distroDefault = "fedora"

preservedEnvironmentVariables = []string{
Expand Down Expand Up @@ -112,8 +115,7 @@ var (
)

var (
ContainerNameDefault string
ContainerNamePrefixDefault = "fedora-toolbox"
ContainerNameDefault string
)

func init() {
Expand All @@ -124,14 +126,17 @@ func init() {
if distroObj, supportedDistro := supportedDistros[hostID]; supportedDistro {
release, err := GetHostVersionID()
if err == nil {
ContainerNamePrefixDefault = distroObj.ContainerNamePrefix
containerNamePrefixDefault = distroObj.ContainerNamePrefix
distroDefault = hostID
releaseDefault = release
}
}
}

ContainerNameDefault = ContainerNamePrefixDefault + "-" + releaseDefault
ContainerNameDefault = containerNamePrefixDefault + "-" + releaseDefault

viper.SetDefault("general.distro", distroDefault)
viper.SetDefault("general.release", releaseDefault)
}

func AskForConfirmation(prompt string) bool {
Expand Down Expand Up @@ -285,7 +290,7 @@ func GetContainerNamePrefixForImage(image string) (string, error) {
return basename, nil
}

func GetDefaultImageForDistro(distro, release string) string {
func getDefaultImageForDistro(distro, release string) string {
if _, supportedDistro := supportedDistros[distro]; !supportedDistro {
distro = "fedora"
}
Expand Down Expand Up @@ -569,6 +574,71 @@ func ImageReferenceHasDomain(image string) bool {
return true
}

func SetUpConfiguration() error {
logrus.Debug("Setting up configuration")

configFiles := []string{
"/etc/containers/toolbox.conf",
}

userConfigDir, err := os.UserConfigDir()
if err != nil {
logrus.Debugf("Setting up configuration: failed to get the user config directory: %s", err)
return errors.New("failed to get the user config directory")
}

userConfigPath := userConfigDir + "/containers/toolbox.conf"
configFiles = append(configFiles, []string{
userConfigPath,
}...)

viper.SetConfigType("toml")

for _, configFile := range configFiles {
viper.SetConfigFile(configFile)

if err := viper.MergeInConfig(); err != nil {
// Seems like Viper's errors can't be examined with
// errors.As.

// Seems like Viper doesn't actually throw
// viper.ConfigFileNotFoundError if a configuration
// file is not found. We still check for it for the
// sake of completion or in case Viper uses it in a
// different version.
_, ok := err.(viper.ConfigFileNotFoundError)
if ok || os.IsNotExist(err) {
logrus.Debugf("Setting up configuration: file %s not found", configFile)
continue
}

if _, ok := err.(viper.ConfigParseError); ok {
logrus.Debugf("Setting up configuration: failed to parse file %s: %s", configFile, err)
return fmt.Errorf("failed to parse file %s", configFile)
}

logrus.Debugf("Setting up configuration: failed to read file %s: %s", configFile, err)
return fmt.Errorf("failed to read file %s", configFile)
}
}

image, release, err := ResolveImageName("", "", "")
if err != nil {
logrus.Debugf("Setting up configuration: failed to resolve image name: %s", err)
return errors.New("failed to resolve image name")
}

container, err := ResolveContainerName("", image, release)
if err != nil {
logrus.Debugf("Setting up configuration: failed to resolve container name: %s", err)
return errors.New("failed to resolve container name")
}

ContainerNameDefault = container

return nil
}

// ShortID shortens provided id to first 12 characters.
func ShortID(id string) string {
if len(id) > idTruncLength {
Expand All @@ -579,7 +649,7 @@ func ShortID(id string) string {

func ParseRelease(distro, release string) (string, error) {
if distro == "" {
distro = distroDefault
distro = viper.GetString("general.distro")
}

if _, supportedDistro := supportedDistros[distro]; !supportedDistro {
Expand Down Expand Up @@ -701,30 +771,41 @@ func ResolveContainerName(container, image, release string) (string, error) {
// If no image name is specified then the base image will reflect the platform of the host (even the version).
//
// If the host system is unknown then the base image will be 'fedora-toolbox' with a default version
func ResolveImageName(distro, image, release string) (string, string, error) {
func ResolveImageName(distroCLI, imageCLI, releaseCLI string) (string, string, error) {
logrus.Debug("Resolving image name")
logrus.Debugf("Distribution: '%s'", distro)
logrus.Debugf("Image: '%s'", image)
logrus.Debugf("Release: '%s'", release)
logrus.Debugf("Distribution (CLI): '%s'", distroCLI)
logrus.Debugf("Image (CLI): '%s'", imageCLI)
logrus.Debugf("Release (CLI): '%s'", releaseCLI)

if distro == "" {
distro = distroDefault
distro, image, release := distroCLI, imageCLI, releaseCLI

if distroCLI == "" {
distro = viper.GetString("general.distro")
}

if distro != distroDefault && release == "" {
if distro != distroDefault && releaseCLI == "" && !viper.InConfig("general.release") {
return "", "", fmt.Errorf("release not found for non-default distribution %s", distro)
}

if release == "" {
release = releaseDefault
release = viper.GetString("general.release")
}

if image == "" {
image = GetDefaultImageForDistro(distro, release)
image = getDefaultImageForDistro(distro, release)
debarshiray marked this conversation as resolved.
Show resolved Hide resolved

if viper.InConfig("general.image") && distroCLI == "" && releaseCLI == "" {
image = viper.GetString("general.image")

release = ImageReferenceGetTag(image)
if release == "" {
release = viper.GetString("general.release")
}
}
} else {
release = ImageReferenceGetTag(image)
if release == "" {
release = releaseDefault
release = viper.GetString("general.release")
HarryMichal marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
1 change: 1 addition & 0 deletions test/system/000-setup.bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
load 'libs/helpers'

@test "test suite: Setup" {
_setup_toolbox_configs
# Cache the default image for the system
_pull_and_cache_distro_image $(get_system_id) $(get_system_version) || die
# Cache all images that will be needed during the tests
Expand Down
29 changes: 29 additions & 0 deletions test/system/101-create.bats
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,32 @@ teardown() {

assert_output --regexp "Created[[:blank:]]+fedora-toolbox-32"
}

@test "create: Create a container with overriden distro option (system-wide)" {
skip_if_system_config_unwritable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these tests actually do anything?

}

@test "create: Create a container with overriden distro option (user-specific)" {
skip_if_user_config_unwritable
}

@test "create: Create a container with overriden release option (system-wide)" {
skip_if_system_config_unwritable
}

@test "create: Create a container with overriden release option (user-specific)" {
skip_if_user_config_unwritable
}

@test "create: Create a container with overriden image option (system-wide)" {
skip_if_system_config_unwritable
}

@test "create: Create a container with overriden image option (user-specific)" {
skip_if_user_config_unwritable
}

@test "create: Create a container with overriden image option (both system-wide + user-specific)" {
skip_if_system_config_unwritable
skip_if_user_config_unwritable
}
1 change: 1 addition & 0 deletions test/system/999-teardown.bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
load 'libs/helpers'

@test "test suite: Teardown" {
_restore_toolbox_configs
_clean_cached_images
}
Loading