Skip to content

Commit

Permalink
Merge pull request clearcontainers#564 from jodh-intel/support-stateless
Browse files Browse the repository at this point in the history
config: Support a stateless system
  • Loading branch information
Julio Montes authored Sep 19, 2017
2 parents 5c8430b + 35575f8 commit b12c15a
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 25 deletions.
32 changes: 24 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ endif

LIBEXECDIR := $(PREFIX)/libexec
SHAREDIR := $(PREFIX)/share
DEFAULTSDIR := $(SHAREDIR)/defaults

PKGDATADIR := $(SHAREDIR)/$(CCDIR)
PKGLIBDIR := $(LOCALSTATEDIR)/lib/$(CCDIR)
Expand Down Expand Up @@ -123,9 +124,16 @@ CONFIG_IN = $(CONFIG).in

DESTTARGET := $(abspath $(DESTBINDIR)/$(TARGET))

DESTCONFDIR := $(DESTDIR)/$(SYSCONFDIR)/$(CCDIR)
DESTCONFDIR := $(DESTDIR)/$(DEFAULTSDIR)/$(CCDIR)
DESTSYSCONFDIR := $(DESTDIR)/$(SYSCONFDIR)/$(CCDIR)

# Main configuration file location for stateless systems
DESTCONFIG := $(abspath $(DESTCONFDIR)/$(CONFIG_FILE))

# Secondary configuration file location. Note that this takes precedence
# over DESTCONFIG.
DESTSYSCONFIG := $(abspath $(DESTSYSCONFDIR)/$(CONFIG_FILE))

DESTSHAREDIR := $(DESTDIR)/$(SHAREDIR)

PAUSEDESTDIR := $(abspath $(DESTDIR)/$(PAUSEROOTPATH)/$(PAUSEBINRELPATH))
Expand All @@ -139,6 +147,7 @@ USER_VARS += BINDIR
USER_VARS += CC_SYSTEM_BUILD
USER_VARS += DESTCONFIG
USER_VARS += DESTDIR
USER_VARS += DESTSYSCONFIG
USER_VARS += DESTTARGET
USER_VARS += GLOBALLOGPATH
USER_VARS += IMAGEPATH
Expand Down Expand Up @@ -215,7 +224,13 @@ const defaultVCPUCount uint32 = $(DEFVCPUS)
const defaultMemSize uint32 = $(DEFMEMSZ) // MiB
const defaultDisableBlockDeviceUse bool = $(DEFDISABLEBLOCK)

// Default config file used by stateless systems.
var defaultRuntimeConfiguration = "$(DESTCONFIG)"

// Alternate config file that takes precedence over
// defaultRuntimeConfiguration.
var defaultSysConfRuntimeConfiguration = "$(DESTSYSCONFIG)"

var defaultProxyPath = "$(PROXYPATH)"
endef

Expand Down Expand Up @@ -339,14 +354,15 @@ show-footer:
show-summary: show-header
@printf "• Summary:\n"
@printf "\n"
@printf "\tClear Containers system build : $(cc_system_build)\n"
@printf "\tClear Containers system build : $(cc_system_build)\n"
@printf "\n"
@printf "\tbinary install path (DESTTARGET) : %s\n" $(DESTTARGET)
@printf "\tconfig install path (DESTCONFIG) : %s\n" $(DESTCONFIG)
@printf "\thypervisor path (QEMUPATH) : %s\n" $(QEMUPATH)
@printf "\tassets path (PKGDATADIR) : %s\n" $(PKGDATADIR)
@printf "\tproxy+shim path (PKGLIBEXECDIR) : %s\n" $(PKGLIBEXECDIR)
@printf "\tpause bundle path (PAUSEROOTPATH) : %s\n" $(PAUSEROOTPATH)
@printf "\tbinary install path (DESTTARGET) : %s\n" $(DESTTARGET)
@printf "\tconfig install path (DESTCONFIG) : %s\n" $(DESTCONFIG)
@printf "\talternate config path (DESTSYSCONFIG) : %s\n" $(DESTSYSCONFIG)
@printf "\thypervisor path (QEMUPATH) : %s\n" $(QEMUPATH)
@printf "\tassets path (PKGDATADIR) : %s\n" $(PKGDATADIR)
@printf "\tproxy+shim path (PKGLIBEXECDIR) : %s\n" $(PKGLIBEXECDIR)
@printf "\tpause bundle path (PAUSEROOTPATH) : %s\n" $(PAUSEROOTPATH)
@printf "\n"


Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,20 @@ See [the contributing document](CONTRIBUTING.md).

## Configuration

The runtime uses a single configuration file called `configuration.toml` which is normally located at `/etc/clear-containers/configuration.toml`.
The runtime uses a single configuration file called `configuration.toml`.
Since the runtime supports a [stateless system](https://clearlinux.org/features/stateless),
it checks for this configuration file in multiple locations. The default
location is `/usr/share/defaults/clear-containers/configuration.toml` for a
standard system. However, if `/etc/clear-containers/configuration.toml`
exists, this will take priority.

To see details of your systems runtime environment (including the location of the configuration file), run:
To see which paths the runtime will check for a configuration source, run:

```bash
$ cc-runtime --cc-show-default-config-paths
```

To see details of your systems runtime environment (including the location of the configuration file being used), run:

```bash
$ cc-runtime cc-env
Expand Down
48 changes: 38 additions & 10 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
goruntime "runtime"
"strings"
Expand Down Expand Up @@ -331,19 +330,16 @@ func loadConfiguration(configPath string, ignoreLogging bool) (resolvedConfigPat
ShimType: defaultShim,
}

var resolved string

if configPath == "" {
configPath = defaultRuntimeConfiguration
resolved, err = getDefaultConfigFile()
} else {
resolved, err = resolvePath(configPath)
}

resolved, err := resolvePath(configPath)
if err != nil {
if os.IsNotExist(err) {
// Make the error clearer than the one returned
// by EvalSymlinks().
return "", "", config, fmt.Errorf("Config file %v does not exist", configPath)
}

return "", "", config, err
return "", "", config, fmt.Errorf("Cannot find usable config file (%v)", err)
}

configData, err := ioutil.ReadFile(resolved)
Expand Down Expand Up @@ -376,3 +372,35 @@ func loadConfiguration(configPath string, ignoreLogging bool) (resolvedConfigPat

return resolved, logfilePath, config, nil
}

// getDefaultConfigFilePaths returns a list of paths that will be
// considered as configuration files in priority order.
func getDefaultConfigFilePaths() []string {
return []string{
// normally below "/etc"
defaultSysConfRuntimeConfiguration,

// normally below "/usr/share"
defaultRuntimeConfiguration,
}
}

// getDefaultConfigFile looks in multiple default locations for a
// configuration file and returns the resolved path for the first file
// found, or an error if no config files can be found.
func getDefaultConfigFile() (string, error) {
var errs []string

for _, file := range getDefaultConfigFilePaths() {
resolved, err := resolvePath(file)
if err != nil {
s := fmt.Sprintf("config file %q unresolvable: %v", file, err)
errs = append(errs, s)
continue
}

return resolved, nil
}

return "", errors.New(strings.Join(errs, ", "))
}
67 changes: 67 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func testLoadConfiguration(t *testing.T, dir string,

// override
defaultRuntimeConfiguration = testConfig.ConfigPath
defaultSysConfRuntimeConfiguration = ""

for _, file := range configFiles {
var err error
Expand Down Expand Up @@ -871,3 +872,69 @@ func TestAgentDefaults(t *testing.T) {
a.PauseRootPath = path
assert.Equal(t, a.pauseRootPath(), path, "custom agent pause root path wrong")
}

func TestGetDefaultConfigFilePaths(t *testing.T) {
assert := assert.New(t)

results := getDefaultConfigFilePaths()
// There should be atleast two config file locations
assert.True(len(results) >= 2)

for _, f := range results {
// Paths cannot be empty
assert.NotNil(f)
}
}

func TestGetDefaultConfigFile(t *testing.T) {
assert := assert.New(t)

tmpdir, err := ioutil.TempDir(testDir, "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)

hypervisor := "qemu"
confDir := filepath.Join(tmpdir, "conf")
sysConfDir := filepath.Join(tmpdir, "sysconf")

for _, dir := range []string{confDir, sysConfDir} {
err = os.MkdirAll(dir, testDirMode)
assert.NoError(err)
}

confDirConfig, err := createAllRuntimeConfigFiles(confDir, hypervisor)
assert.NoError(err)

sysConfDirConfig, err := createAllRuntimeConfigFiles(sysConfDir, hypervisor)
assert.NoError(err)

savedConf := defaultRuntimeConfiguration
savedSysConf := defaultSysConfRuntimeConfiguration

defaultRuntimeConfiguration = confDirConfig.ConfigPath
defaultSysConfRuntimeConfiguration = sysConfDirConfig.ConfigPath

defer func() {
defaultRuntimeConfiguration = savedConf
defaultSysConfRuntimeConfiguration = savedSysConf

}()

got, err := getDefaultConfigFile()
assert.NoError(err)
// defaultSysConfRuntimeConfiguration has priority over defaultRuntimeConfiguration
assert.Equal(got, defaultSysConfRuntimeConfiguration)

// force defaultRuntimeConfiguration to be returned
os.Remove(defaultSysConfRuntimeConfiguration)

got, err = getDefaultConfigFile()
assert.NoError(err)
assert.Equal(got, defaultRuntimeConfiguration)

// force error
os.Remove(defaultRuntimeConfiguration)

_, err = getDefaultConfigFile()
assert.Error(err)
}
6 changes: 3 additions & 3 deletions docs/architecture/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ library.
### Configuration

The runtime uses a TOML format configuration file called `configuration.toml`. By
default this file is installed in the `/etc/clear-containers` directory and
contains various settings such as the paths to the hypervisor, the guest
kernel and the mini-OS image.
default this file is installed in the `/usr/share/defaults/clear-containers`
directory and contains various settings such as the paths to the hypervisor,
the guest kernel and the mini-OS image.

Most users will not need to modify the configuration file.

Expand Down
2 changes: 1 addition & 1 deletion docs/developers-clear-containers-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ See [the upgrading document](upgrading.md) for further details.
$ # (note that this is only an example using default paths).
$ sudo sed -i.bak -e 's!^\(image = ".*"\)!# \1 \
image = "/usr/share/clear-containers/container.img"!g' \
/etc/clear-containers/configuration.toml
/usr/share/defaults/clear-containers/configuration.toml

For more details on the runtime's build system, run:
Expand Down
2 changes: 1 addition & 1 deletion installation/centos-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ sudo yum -y install cc-runtime cc-proxy cc-shim linux-container clear-containers
# rather than the OBS default values.
sudo -E prefix_dir="${prefix_dir}" sed -i -e \
"s,^path = \"/usr/bin/qemu-system-x86_64\",path = \"${prefix_dir}/bin/qemu-system-x86_64\",g" \
/etc/clear-containers/configuration.toml
/usr/share/defaults/clear-containers/configuration.toml

# Configure CC by default
service_dir="/etc/systemd/system/docker.service.d"
Expand Down
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ var runtimeFlags = []cli.Flag{
Value: defaultRootDirectory,
Usage: "root directory for storage of container state (this should be located in tmpfs)",
},
cli.BoolFlag{
Name: "cc-show-default-config-paths",
Usage: "show config file paths that will be checked for (in order)",
},
}

// runtimeCommands is the list of supported command-line (sub-)
Expand Down Expand Up @@ -132,6 +136,16 @@ var savedCLIErrWriter = cli.ErrWriter
// beforeSubcommands is the function to perform preliminary checks
// before command-line parsing occurs.
func beforeSubcommands(context *cli.Context) error {
if context.GlobalBool("cc-show-default-config-paths") {
files := getDefaultConfigFilePaths()

for _, file := range files {
fmt.Fprintf(defaultOutputFile, "%s\n", file)
}

exit(0)
}

if userWantsUsage(context) || (context.NArg() == 1 && (context.Args()[0] == "cc-check")) {
// No setup required if the user just
// wants to see the usage statement or are
Expand Down
74 changes: 74 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ func init() {
panic("ERROR: invalid build: commit not set")
}

if defaultSysConfRuntimeConfiguration == "" {
panic("ERROR: invalid build: defaultSysConfRuntimeConfiguration not set")
}

if defaultRuntimeConfiguration == "" {
panic("ERROR: invalid build: defaultRuntimeConfiguration not set")
}

fmt.Printf("INFO: switching to fake virtcontainers implementation for testing\n")
vci = testingImpl

Expand Down Expand Up @@ -749,6 +757,72 @@ func TestMainBeforeSubCommandsLoadConfigurationFail(t *testing.T) {
}
}

func TestMainBeforeSubCommandsShowCCConfigPaths(t *testing.T) {
assert := assert.New(t)

tmpdir, err := ioutil.TempDir(testDir, "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)

app := cli.NewApp()

set := flag.NewFlagSet("", 0)
set.Bool("cc-show-default-config-paths", true, "")

ctx := cli.NewContext(app, set, nil)

savedExitFunc := exitFunc

exitStatus := 99
exitFunc = func(status int) { exitStatus = status }

defer func() {
exitFunc = savedExitFunc
}()

savedOutputFile := defaultOutputFile

defer func() {
resetCLIGlobals()
defaultOutputFile = savedOutputFile
}()

output := filepath.Join(tmpdir, "output")
f, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_SYNC, testFileMode)
assert.NoError(err)
defer f.Close()

defaultOutputFile = f

setCLIGlobals()

_ = beforeSubcommands(ctx)
assert.Equal(exitStatus, 0)

text, err := getFileContents(output)
assert.NoError(err)

lines := strings.Split(text, "\n")

// Remove last line if empty
length := len(lines)
last := lines[length-1]
if last == "" {
lines = lines[:length-1]
}

assert.Equal(len(lines), 2)

for i, line := range lines {
switch i {
case 0:
assert.Equal(line, defaultSysConfRuntimeConfiguration)
case 1:
assert.Equal(line, defaultRuntimeConfiguration)
}
}
}

func TestMainFatal(t *testing.T) {
assert := assert.New(t)

Expand Down
Loading

0 comments on commit b12c15a

Please sign in to comment.