Removed dependency on DCOS_CONFIG env var

This commit is contained in:
Michael Gummelt
2015-08-07 16:14:53 -07:00
parent 5cbb6c3882
commit ceb8281013
9 changed files with 84 additions and 143 deletions

View File

@@ -1,6 +1,6 @@
DCOS Command Line Interface
===========================
The DCOS Command Line Interface (CLI) is a cross-platform command line utility
The DCOS Command Line Interface (CLI) is a cross-platform command line utility
that provides a user-friendly yet powerful way to manage DCOS installations.
Installation and Usage
@@ -30,7 +30,7 @@ The example below installs every package available in the DCOS repository::
Using the CLI without DCOS
--------------------------
You may optionally configure the DCOS CLI to work with open source Mesos and
You may optionally configure the DCOS CLI to work with open source Mesos and
Marathon_ by setting the following properties::
dcos config set core.mesos_master_url http://<mesos-master-host>:5050
dcos config set marathon.url http://<marathon-host>:8080
@@ -112,12 +112,9 @@ Running
Tox will run unit and integration tests in both Python environments using a
temporarily created virtualenv.
You should ensure :code:`DCOS_CONFIG` is set and that the config file points
to the Marathon instance you want to use for integration tests. If you're
happy to use the default test configuration which assumes there is a Marathon
instance running on localhost, set :code:`DCOS_CONFIG` as follows::
export DCOS_CONFIG=$(pwd)/tests/data/dcos.toml
You can set :code:`DCOS_CONFIG` to a config file that points to a DCOS
cluster you want to use for integration tests. This defaults to
:code:`~/.dcos/dcos.toml`
If you are testing against the DCOS Image you can configure the URL to the
Exhibitor::

View File

@@ -6,12 +6,8 @@ else
BIN_DIR=$PWD/bin
fi
# real, absolute path to BIN_DIR
FULL_BIN_PATH=$(python -c "import os; print(os.path.realpath('$BIN_DIR'))")
# ensure BIN_DIR is prepended to PATH
expr "$PATH" : "${FULL_BIN_PATH}.*" > /dev/null || export PATH=$FULL_BIN_PATH:$PATH
export DCOS_CONFIG=~/.dcos/dcos.toml
if [ ! -f "$DCOS_CONFIG" ]; then
mkdir -p $(dirname "$DCOS_CONFIG")
touch "$DCOS_CONFIG"
fi

View File

@@ -24,15 +24,12 @@ Positional Arguments:
import collections
import copy
import json
import os
import dcoscli
import docopt
import pkg_resources
import six
import toml
from dcos import (cmds, config, constants, emitting, http, jsonitem,
subcommand, util)
from dcos import cmds, config, emitting, http, jsonitem, subcommand, util
from dcos.errors import DCOSException
from dcoscli import analytics
@@ -153,7 +150,7 @@ def _set(name, value):
:rtype: int
"""
config_path, toml_config = _load_config()
toml_config = util.get_config(True)
section, subkey = _split_key(name)
@@ -172,7 +169,7 @@ def _set(name, value):
_check_config(toml_config_pre, toml_config)
_save_config_file(config_path, toml_config)
config.save(toml_config)
return 0
@@ -182,7 +179,7 @@ def _append(name, value):
:rtype: int
"""
config_path, toml_config = _load_config()
toml_config = util.get_config(True)
python_value = _parse_array_item(name, value)
toml_config_pre = copy.deepcopy(toml_config)
@@ -194,7 +191,7 @@ def _append(name, value):
_check_config(toml_config_pre, toml_config)
_save_config_file(config_path, toml_config)
config.save(toml_config)
return 0
@@ -204,7 +201,7 @@ def _prepend(name, value):
:rtype: int
"""
config_path, toml_config = _load_config()
toml_config = util.get_config(True)
python_value = _parse_array_item(name, value)
@@ -215,7 +212,7 @@ def _prepend(name, value):
toml_config[name] = python_value + toml_config.get(name, [])
_check_config(toml_config_pre, toml_config)
_save_config_file(config_path, toml_config)
config.save(toml_config)
return 0
@@ -225,7 +222,7 @@ def _unset(name, index):
:rtype: int
"""
config_path, toml_config = _load_config()
toml_config = util.get_config(True)
toml_config_pre = copy.deepcopy(toml_config)
section = name.split(".", 1)[0]
if section not in toml_config_pre._dictionary:
@@ -251,7 +248,7 @@ def _unset(name, index):
raise DCOSException(
'Unsetting based on an index is only supported for lists')
_save_config_file(config_path, toml_config)
config.save(toml_config)
return 0
@@ -261,7 +258,7 @@ def _show(name):
:rtype: int
"""
_, toml_config = _load_config()
toml_config = util.get_config(True)
if name is not None:
value = toml_config.get(name)
@@ -285,7 +282,7 @@ def _validate():
:rtype: int
"""
_, toml_config = _load_config()
toml_config = util.get_config(True)
errs = util.validate_json(toml_config._dictionary,
_generate_root_schema(toml_config))
@@ -338,29 +335,6 @@ def _generate_choice_msg(name, value):
return message
def _load_config():
"""
:returns: process status
:rtype: int
"""
config_path = os.environ[constants.DCOS_CONFIG_ENV]
return (config_path, config.mutable_load_from_path(config_path))
def _save_config_file(config_path, toml_config):
"""
:param config_path: path to configuration file.
:type config_path: str
:param toml_config: TOML configuration object
:type toml_config: MutableToml or Toml
"""
serial = toml.dumps(toml_config._dictionary)
with util.open_file(config_path, 'w') as config_file:
config_file.write(serial)
def _get_config_schema(command):
"""
:param command: the subcommand name

View File

@@ -29,6 +29,7 @@ Environment Variables:
DCOS_CONFIG This environment variable points to the
location of the DCOS configuration file.
[default: ~/.dcos/dcos.toml]
DCOS_DEBUG If set then enable further debug messages which
are sent to stdout.
@@ -59,9 +60,6 @@ def main():
def _main():
signal.signal(signal.SIGINT, signal_handler)
if not _is_valid_configuration():
return 1
args = docopt.docopt(
__doc__,
version='dcos version {}'.format(dcoscli.version),
@@ -128,27 +126,6 @@ def _config_debug_environ(is_debug):
os.environ.pop(constants.DCOS_DEBUG_ENV, None)
def _is_valid_configuration():
"""Validates running environment
:returns: True if the environment is configure correctly; False otherwise.
:rtype: bool
"""
dcos_config = os.environ.get(constants.DCOS_CONFIG_ENV)
if dcos_config is None:
msg = 'Environment variable {!r} must be set to the DCOS config file.'
emitter.publish(msg.format(constants.DCOS_CONFIG_ENV))
return False
if not os.path.isfile(dcos_config):
msg = 'Environment variable {!r} maps to {!r} and it is not a file.'
emitter.publish(msg.format(constants.DCOS_CONFIG_ENV, dcos_config))
return False
return True
def signal_handler(signal, frame):
emitter.publish(
errors.DefaultError("User interrupted command with Ctrl-C"))

View File

@@ -1,7 +1,3 @@
import os
from dcos import constants
from .common import assert_command, exec_command
@@ -62,6 +58,7 @@ Environment Variables:
DCOS_CONFIG This environment variable points to the
location of the DCOS configuration file.
[default: ~/.dcos/dcos.toml]
DCOS_DEBUG If set then enable further debug messages which
are sent to stdout.
@@ -76,38 +73,6 @@ def test_version():
stdout=b'dcos version SNAPSHOT\n')
def test_missing_dcos_config():
env = os.environ.copy()
del env['DCOS_CONFIG']
env.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
})
stdout = (b"Environment variable 'DCOS_CONFIG' must be set "
b"to the DCOS config file.\n")
assert_command(['dcos'],
stdout=stdout,
returncode=1,
env=env)
def test_dcos_config_not_a_file():
env = os.environ.copy()
env.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
'DCOS_CONFIG': 'missing/file',
})
stdout = (b"Environment variable 'DCOS_CONFIG' maps to "
b"'missing/file' and it is not a file.\n")
assert_command(['dcos'],
returncode=1,
stdout=stdout,
env=env)
def test_log_level_flag():
returncode, stdout, stderr = exec_command(
['dcos', '--log-level=info', 'config', '--info'])

View File

@@ -1,11 +1,9 @@
import json
import os
import sys
import uuid
import pkg_resources
import toml
from dcos import config, constants, emitting, errors, http, jsonitem, util
from dcos import config, emitting, errors, http, jsonitem, util
from dcos.errors import DCOSException
from six import iteritems
@@ -124,8 +122,7 @@ def _save_auth_keys(key_dict):
:rtype: None
"""
config_path = os.environ[constants.DCOS_CONFIG_ENV]
toml_config = config.mutable_load_from_path(config_path)
toml_config = util.get_config(True)
section = 'core'
config_schema = json.loads(
@@ -137,8 +134,5 @@ def _save_auth_keys(key_dict):
name = '{}.{}'.format(section, k)
toml_config[name] = python_value
serial = toml.dumps(toml_config._dictionary)
with util.open_file(config_path, 'w') as config_file:
config_file.write(serial)
config.save(toml_config)
return None

View File

@@ -4,30 +4,33 @@ import toml
from dcos import util
def mutable_load_from_path(path):
"""Loads a TOML file from the path
:param path: Path to the TOML file
:type path: str
:returns: Mutable map for the configuration file
:rtype: MutableToml
"""
with util.open_file(path) as config_file:
return MutableToml(toml.loads(config_file.read()))
def load_from_path(path):
def load_from_path(path, mutable=False):
"""Loads a TOML file from the path
:param path: Path to the TOML file
:type path: str
:param mutable: True if the returned Toml object should be mutable
:type mutable: boolean
:returns: Map for the configuration file
:rtype: Toml
:rtype: Toml | MutableToml
"""
with util.open_file(path) as config_file:
return Toml(toml.loads(config_file.read()))
util.ensure_file_exists(path)
with util.open_file(path, 'r') as config_file:
toml_obj = toml.loads(config_file.read())
return (MutableToml if mutable else Toml)(toml_obj)
def save(toml_config):
"""
:param toml_config: TOML configuration object
:type toml_config: MutableToml or Toml
"""
serial = toml.dumps(toml_config._dictionary)
path = util.get_config_path()
with util.open_file(path, 'w') as config_file:
config_file.write(serial)
def _get_path(config, path):

View File

@@ -275,7 +275,7 @@ def install(pkg, revision, options):
"""
pkg_dir = package_dir(pkg.name())
util.ensure_dir(pkg_dir)
util.ensure_dir_exists(pkg_dir)
_write_package_json(pkg, revision)
_write_package_revision(pkg, revision)

View File

@@ -74,7 +74,7 @@ def temptext():
shutil.rmtree(path, ignore_errors=True)
def ensure_dir(directory):
def ensure_dir_exists(directory):
"""If `directory` does not exist, create it.
:param directory: path to the directory
@@ -92,6 +92,22 @@ def ensure_dir(directory):
'Cannot create directory [{}]: {}'.format(directory, e))
def ensure_file_exists(path):
""" Create file if it doesn't exist
:param path: path of file to create
:type path: str
:rtype: None
"""
if not os.path.exists(path):
try:
open(path, 'w').close()
except IOError as e:
raise DCOSException(
'Cannot create file [{}]: {}'.format(path, e))
def read_file(path):
"""
:param path: path to file
@@ -106,17 +122,36 @@ def read_file(path):
return file_.read()
def get_config():
def get_config_path():
""" Returns the path to the DCOS config file.
:returns: path to the DCOS config file
:rtype: str
"""
default = os.path.expanduser(
os.path.join("~",
constants.DCOS_DIR,
'dcos.toml'))
return os.environ.get(constants.DCOS_CONFIG_ENV, default)
def get_config(mutable=False):
""" Returns the DCOS configuration object
:param mutable: True if the returned Toml object should be mutable
:type mutable: boolean
:returns: Configuration object
:rtype: Toml
:rtype: Toml | MutableToml
"""
# avoid circular import
from dcos import config
return config.load_from_path(
os.environ[constants.DCOS_CONFIG_ENV])
path = get_config_path()
return config.load_from_path(path, mutable)
def get_config_vals(keys, config=None):