Skip to content

Commit

Permalink
Merge pull request #183 from mesosphere/pre-install-confirmation
Browse files Browse the repository at this point in the history
Output pre-install notes on package install.
  • Loading branch information
jsancio committed May 27, 2015
2 parents 8bec3df + 5e506bf commit d5d99cb
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 40 deletions.
45 changes: 41 additions & 4 deletions cli/dcoscli/package/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
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
Expand All @@ -19,6 +18,8 @@
-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
Expand Down Expand Up @@ -52,6 +53,8 @@
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()
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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
"""
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions cli/tests/data/dcos.toml
Original file line number Diff line number Diff line change
@@ -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"
4 changes: 2 additions & 2 deletions cli/tests/data/missing_params_dcos.toml
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions cli/tests/data/package/assume_no.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
no

2 changes: 2 additions & 0 deletions cli/tests/data/package/assume_yes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
yes

13 changes: 7 additions & 6 deletions cli/tests/integrations/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions cli/tests/integrations/cli/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -80,7 +80,7 @@ def test_list_property(env):


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):
Expand All @@ -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):
Expand Down
70 changes: 49 additions & 21 deletions cli/tests/integrations/cli/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ def test_package():
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
Expand All @@ -29,6 +28,8 @@ def test_package():
-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
Expand Down Expand Up @@ -241,7 +242,7 @@ def test_describe():


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
Expand Down Expand Up @@ -328,12 +329,12 @@ def test_package_metadata():


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)
Expand Down Expand Up @@ -440,8 +441,9 @@ def test_list_installed():
"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": [
Expand Down Expand Up @@ -474,6 +476,22 @@ def test_list_installed():
_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()

Expand Down Expand Up @@ -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"""\
[
Expand Down Expand Up @@ -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''
Expand All @@ -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=[]):
Expand All @@ -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'',
Expand All @@ -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)

0 comments on commit d5d99cb

Please sign in to comment.