Merge pull request #183 from mesosphere/pre-install-confirmation
Output pre-install notes on package install.
This commit is contained in:
@@ -6,8 +6,7 @@ Usage:
|
||||
dcos package describe [--app --options=<file> --cli] <package_name>
|
||||
dcos package info
|
||||
dcos package install [--cli | [--app --app-id=<app_id>]]
|
||||
[--options=<file>]
|
||||
<package_name>
|
||||
[--options=<file> --yes] <package_name>
|
||||
dcos package list-installed [--endpoints --app-id=<app-id> <package_name>]
|
||||
dcos package search [<query>]
|
||||
dcos package sources
|
||||
@@ -19,6 +18,8 @@ Options:
|
||||
-h, --help Show this screen
|
||||
--info Show a short description of this subcommand
|
||||
--version Show version
|
||||
--yes Assume "yes" is the answer to all prompts and run
|
||||
non-interactively
|
||||
--all Apply the operation to all matching packages
|
||||
--app Apply the operation only to the package's application
|
||||
--app-id=<app-id> The application id
|
||||
@@ -52,6 +53,8 @@ import pkg_resources
|
||||
from dcos import cmds, emitting, marathon, options, package, subcommand, util
|
||||
from dcos.errors import DCOSException
|
||||
|
||||
from six.moves import input as user_input
|
||||
|
||||
logger = util.get_logger(__name__)
|
||||
|
||||
emitter = emitting.FlatEmitter()
|
||||
@@ -100,7 +103,7 @@ def _cmds():
|
||||
cmds.Command(
|
||||
hierarchy=['package', 'install'],
|
||||
arg_keys=['<package_name>', '--options', '--app-id', '--cli',
|
||||
'--app'],
|
||||
'--app', '--yes'],
|
||||
function=_install),
|
||||
|
||||
cmds.Command(
|
||||
@@ -240,7 +243,32 @@ def _user_options(path):
|
||||
return util.load_json(options_file)
|
||||
|
||||
|
||||
def _install(package_name, options_path, app_id, cli, app):
|
||||
def _confirm(prompt, yes):
|
||||
"""
|
||||
:param prompt: message to display to the terminal
|
||||
:type prompt: str
|
||||
:param yes: whether to assume that the user responded with yes
|
||||
:type yes: bool
|
||||
:returns: True if the user responded with yes; False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
if yes:
|
||||
return True
|
||||
else:
|
||||
while True:
|
||||
emitter.publish('{} [yes/no]'.format(prompt))
|
||||
response = user_input().lower()
|
||||
if response == 'yes' or response == 'y':
|
||||
return True
|
||||
elif response == 'no' or response == 'n':
|
||||
return False
|
||||
else:
|
||||
emitter.publish(
|
||||
"'{}' is not a valid response.".format(response))
|
||||
|
||||
|
||||
def _install(package_name, options_path, app_id, cli, app, yes):
|
||||
"""Install the specified package.
|
||||
|
||||
:param package_name: the package to install
|
||||
@@ -253,6 +281,8 @@ def _install(package_name, options_path, app_id, cli, app):
|
||||
:type cli: bool
|
||||
:param app: indicate if the application should be installed
|
||||
:type app: bool
|
||||
:param yes: automatically assume yes to all prompts
|
||||
:type yes: bool
|
||||
:returns: process status
|
||||
:rtype: int
|
||||
"""
|
||||
@@ -273,6 +303,13 @@ def _install(package_name, options_path, app_id, cli, app):
|
||||
# TODO(CD): Make package version to install configurable
|
||||
pkg_version = pkg.latest_version()
|
||||
|
||||
pre_install_notes = pkg.package_json(pkg_version).get('preInstallNotes')
|
||||
if pre_install_notes:
|
||||
emitter.publish(pre_install_notes)
|
||||
if not _confirm('Continue installing?', yes):
|
||||
emitter.publish('Exiting installation.')
|
||||
return 0
|
||||
|
||||
user_options = _user_options(options_path)
|
||||
|
||||
options = pkg.options(pkg_version, user_options)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[core]
|
||||
dcos_url = "http://localhost:5080"
|
||||
dcos_url = "http://172.17.8.101"
|
||||
email = "test@mail.com"
|
||||
reporting = false
|
||||
[package]
|
||||
cache = "tmp/cache"
|
||||
sources = [ "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",]
|
||||
cache = "tmp/cache"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[core]
|
||||
reporting = false
|
||||
email = "test@mail.com"
|
||||
reporting = false
|
||||
[package]
|
||||
cache = "true"
|
||||
sources = [ "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",]
|
||||
cache = "true"
|
||||
|
||||
2
cli/tests/data/package/assume_no.txt
Normal file
2
cli/tests/data/package/assume_no.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
no
|
||||
|
||||
2
cli/tests/data/package/assume_yes.txt
Normal file
2
cli/tests/data/package/assume_yes.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
yes
|
||||
|
||||
@@ -33,12 +33,13 @@ def exec_command(cmd, env=None, stdin=None):
|
||||
return (process.returncode, stdout, stderr)
|
||||
|
||||
|
||||
def assert_command(cmd,
|
||||
returncode=0,
|
||||
stdout=b'',
|
||||
stderr=b'',
|
||||
env=None,
|
||||
stdin=None):
|
||||
def assert_command(
|
||||
cmd,
|
||||
returncode=0,
|
||||
stdout=b'',
|
||||
stderr=b'',
|
||||
env=None,
|
||||
stdin=None):
|
||||
"""Execute CLI command and assert expected behavior.
|
||||
|
||||
:param cmd: Program and arguments
|
||||
|
||||
@@ -67,7 +67,7 @@ def test_version():
|
||||
|
||||
|
||||
def test_list_property(env):
|
||||
stdout = b"""core.dcos_url=http://localhost:5080
|
||||
stdout = b"""core.dcos_url=http://172.17.8.101
|
||||
core.email=test@mail.com
|
||||
core.reporting=False
|
||||
package.cache=tmp/cache
|
||||
@@ -80,7 +80,7 @@ package.sources=['git://github.com/mesosphere/universe.git', \
|
||||
|
||||
|
||||
def test_get_existing_string_property(env):
|
||||
_get_value('core.dcos_url', 'http://localhost:5080', env)
|
||||
_get_value('core.dcos_url', 'http://172.17.8.101', env)
|
||||
|
||||
|
||||
def test_get_existing_boolean_property(env):
|
||||
@@ -105,9 +105,9 @@ def test_get_top_property(env):
|
||||
|
||||
|
||||
def test_set_existing_string_property(env):
|
||||
_set_value('core.dcos_url', 'http://localhost:5081', env)
|
||||
_get_value('core.dcos_url', 'http://localhost:5081', env)
|
||||
_set_value('core.dcos_url', 'http://localhost:5080', env)
|
||||
_set_value('core.dcos_url', 'http://172.17.8.101:5081', env)
|
||||
_get_value('core.dcos_url', 'http://172.17.8.101:5081', env)
|
||||
_set_value('core.dcos_url', 'http://172.17.8.101', env)
|
||||
|
||||
|
||||
def test_set_existing_boolean_property(env):
|
||||
|
||||
@@ -16,8 +16,7 @@ Usage:
|
||||
dcos package describe [--app --options=<file> --cli] <package_name>
|
||||
dcos package info
|
||||
dcos package install [--cli | [--app --app-id=<app_id>]]
|
||||
[--options=<file>]
|
||||
<package_name>
|
||||
[--options=<file> --yes] <package_name>
|
||||
dcos package list-installed [--endpoints --app-id=<app-id> <package_name>]
|
||||
dcos package search [<query>]
|
||||
dcos package sources
|
||||
@@ -29,6 +28,8 @@ Options:
|
||||
-h, --help Show this screen
|
||||
--info Show a short description of this subcommand
|
||||
--version Show version
|
||||
--yes Assume "yes" is the answer to all prompts and run
|
||||
non-interactively
|
||||
--all Apply the operation to all matching packages
|
||||
--app Apply the operation only to the package's application
|
||||
--app-id=<app-id> The application id
|
||||
@@ -241,7 +242,7 @@ icon-service-marathon-small.png"
|
||||
|
||||
|
||||
def test_bad_install():
|
||||
args = ['--options=tests/data/package/chronos-bad.json']
|
||||
args = ['--options=tests/data/package/chronos-bad.json', '--yes']
|
||||
stderr = b"""Error: False is not of type 'string'
|
||||
Path: chronos.zk-hosts
|
||||
Value: false
|
||||
@@ -328,12 +329,12 @@ CJdfQ=="""
|
||||
|
||||
|
||||
def test_install_with_id():
|
||||
args = ['--app-id=chronos-1']
|
||||
args = ['--app-id=chronos-1', '--yes']
|
||||
stdout = (b"""Installing package [chronos] version [2.3.4] with app """
|
||||
b"""id [chronos-1]\n""")
|
||||
_install_chronos(args=args, stdout=stdout)
|
||||
|
||||
args = ['--app-id=chronos-2']
|
||||
args = ['--app-id=chronos-2', '--yes']
|
||||
stdout = (b"""Installing package [chronos] version [2.3.4] with app """
|
||||
b"""id [chronos-2]\n""")
|
||||
_install_chronos(args=args, stdout=stdout)
|
||||
@@ -440,8 +441,9 @@ service-chronos-small.png"
|
||||
"packageSource": "git://github.com/mesosphere/universe.git",
|
||||
"postInstallNotes": "Chronos DCOS Service has been successfully installed!\
|
||||
\\nWe recommend a minimum of one node with at least 1 CPU and 2GB of RAM \
|
||||
available for the Chronos Service.\\n\\n\\tDocumentation: https://github.com/\
|
||||
mesos/chronos\\n\\tIssues: https:/github.com/mesos/chronos/issues",
|
||||
available for the Chronos Service.\\n\\n\\tDocumentation: \
|
||||
http://mesos.github.io/chronos\\n\\tIssues: https://github.com/mesos/\
|
||||
chronos/issues",
|
||||
"releaseVersion": "0",
|
||||
"scm": "https://github.com/mesos/chronos.git",
|
||||
"tags": [
|
||||
@@ -474,6 +476,22 @@ mesos/chronos\\n\\tIssues: https:/github.com/mesos/chronos/issues",
|
||||
_uninstall_chronos()
|
||||
|
||||
|
||||
def test_install_yes():
|
||||
with open('tests/data/package/assume_yes.txt') as yes_file:
|
||||
_install_helloworld(stdin=yes_file)
|
||||
_uninstall_helloworld()
|
||||
|
||||
|
||||
def test_install_no():
|
||||
with open('tests/data/package/assume_no.txt') as no_file:
|
||||
_install_helloworld(
|
||||
args=[],
|
||||
stdin=no_file,
|
||||
stdout=b'A sample pre-installation message\n'
|
||||
b'Continue installing? [yes/no]\n'
|
||||
b'Exiting installation.\n')
|
||||
|
||||
|
||||
def test_list_installed_cli():
|
||||
_install_helloworld()
|
||||
|
||||
@@ -508,9 +526,10 @@ def test_list_installed_cli():
|
||||
|
||||
_uninstall_helloworld()
|
||||
|
||||
stdout = (b"Installing CLI subcommand for package [helloworld]\n"
|
||||
stdout = (b"A sample pre-installation message\n"
|
||||
b"Installing CLI subcommand for package [helloworld]\n"
|
||||
b"A sample post-installation message\n")
|
||||
_install_helloworld(args=['--cli'], stdout=stdout)
|
||||
_install_helloworld(args=['--cli', '--yes'], stdout=stdout)
|
||||
|
||||
stdout = b"""\
|
||||
[
|
||||
@@ -572,7 +591,7 @@ def test_search():
|
||||
for registry in registries:
|
||||
# assert the number of packages is gte the number at the time
|
||||
# this test was written
|
||||
assert len(registry['packages']) >= 8
|
||||
assert len(registry['packages']) >= 7
|
||||
|
||||
assert returncode == 0
|
||||
assert stderr == b''
|
||||
@@ -590,13 +609,16 @@ def get_app_labels(app_id):
|
||||
|
||||
|
||||
def _install_helloworld(
|
||||
args=[],
|
||||
stdout=b"""Installing package [helloworld] version [0.1.0]
|
||||
Installing CLI subcommand for package [helloworld]
|
||||
A sample post-installation message
|
||||
"""):
|
||||
assert_command(['dcos', 'package', 'install', 'helloworld'] + args,
|
||||
stdout=stdout)
|
||||
args=['--yes'],
|
||||
stdout=b'A sample pre-installation message\n'
|
||||
b'Installing package [helloworld] version [0.1.0]\n'
|
||||
b'Installing CLI subcommand for package [helloworld]\n'
|
||||
b'A sample post-installation message\n',
|
||||
stdin=None):
|
||||
assert_command(
|
||||
['dcos', 'package', 'install', 'helloworld'] + args,
|
||||
stdout=stdout,
|
||||
stdin=stdin)
|
||||
|
||||
|
||||
def _uninstall_helloworld(args=[]):
|
||||
@@ -609,7 +631,7 @@ def _uninstall_chronos(args=[], returncode=0, stdout=b'', stderr=b''):
|
||||
|
||||
|
||||
def _install_chronos(
|
||||
args=[],
|
||||
args=['--yes'],
|
||||
returncode=0,
|
||||
stdout=b'Installing package [chronos] version [2.3.4]\n',
|
||||
stderr=b'',
|
||||
@@ -618,8 +640,14 @@ def _install_chronos(
|
||||
b'with at least 1 CPU and 2GB of RAM available for '
|
||||
b'''the Chronos Service.
|
||||
|
||||
\tDocumentation: https://github.com/mesos/chronos
|
||||
\tIssues: https:/github.com/mesos/chronos/issues\n'''):
|
||||
\tDocumentation: http://mesos.github.io/chronos
|
||||
\tIssues: https://github.com/mesos/chronos/issues\n''',
|
||||
stdin=None):
|
||||
|
||||
cmd = ['dcos', 'package', 'install', 'chronos'] + args
|
||||
assert_command(cmd, returncode, stdout + postInstallNotes, stderr)
|
||||
assert_command(
|
||||
cmd,
|
||||
returncode,
|
||||
stdout + postInstallNotes,
|
||||
stderr,
|
||||
stdin=stdin)
|
||||
|
||||
Reference in New Issue
Block a user