Merge pull request #42 from mesosphere/dcos-319-restart
dcos-319 Implements restarting tasks for app
This commit is contained in:
@@ -148,7 +148,10 @@ class Client(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
url = self._create_url('v2/apps')
|
url = self._create_url('v2/apps')
|
||||||
|
|
||||||
|
logger.info('Getting %r', url)
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
|
logger.info('Got (%r): %r', response.status_code, response.json())
|
||||||
|
|
||||||
if _success(response.status_code):
|
if _success(response.status_code):
|
||||||
apps = response.json()['apps']
|
apps = response.json()['apps']
|
||||||
@@ -197,10 +200,10 @@ class Client(object):
|
|||||||
|
|
||||||
app_id = normalize_app_id(app_id)
|
app_id = normalize_app_id(app_id)
|
||||||
|
|
||||||
if force is None or not force:
|
if not force:
|
||||||
params = None
|
params = None
|
||||||
else:
|
else:
|
||||||
params = {'force': True}
|
params = {'force': 'true'}
|
||||||
|
|
||||||
url = self._create_url('v2/apps{}'.format(app_id), params)
|
url = self._create_url('v2/apps{}'.format(app_id), params)
|
||||||
|
|
||||||
@@ -226,17 +229,18 @@ class Client(object):
|
|||||||
:rtype: (bool, Error)
|
:rtype: (bool, Error)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if force is None:
|
|
||||||
force = False
|
|
||||||
|
|
||||||
app_id = normalize_app_id(app_id)
|
app_id = normalize_app_id(app_id)
|
||||||
|
|
||||||
|
if not force:
|
||||||
params = None
|
params = None
|
||||||
if force:
|
else:
|
||||||
params = {'force': True}
|
params = {'force': 'true'}
|
||||||
|
|
||||||
url = self._create_url('v2/apps{}'.format(app_id), params)
|
url = self._create_url('v2/apps{}'.format(app_id), params)
|
||||||
|
|
||||||
|
logger.info('Putting to %r', url)
|
||||||
response = requests.put(url, json={'instances': int(instances)})
|
response = requests.put(url, json={'instances': int(instances)})
|
||||||
|
logger.info('Got (%r): %r', response.status_code, response.json())
|
||||||
|
|
||||||
if _success(response.status_code):
|
if _success(response.status_code):
|
||||||
deployment = response.json()['deploymentId']
|
deployment = response.json()['deploymentId']
|
||||||
@@ -268,26 +272,56 @@ class Client(object):
|
|||||||
:rtype: Error
|
:rtype: Error
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if force is None:
|
|
||||||
force = False
|
|
||||||
|
|
||||||
app_id = normalize_app_id(app_id)
|
app_id = normalize_app_id(app_id)
|
||||||
|
|
||||||
|
if not force:
|
||||||
params = None
|
params = None
|
||||||
if force:
|
else:
|
||||||
params = {'force': True}
|
params = {'force': 'true'}
|
||||||
|
|
||||||
url = self._create_url('v2/apps{}'.format(app_id), params)
|
url = self._create_url('v2/apps{}'.format(app_id), params)
|
||||||
|
|
||||||
|
logger.info('Deleting %r', url)
|
||||||
response = requests.delete(url)
|
response = requests.delete(url)
|
||||||
|
logger.info('Got (%r)', response.status_code)
|
||||||
|
|
||||||
if _success(response.status_code):
|
if _success(response.status_code):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return self._response_to_error(response)
|
return self._response_to_error(response)
|
||||||
|
|
||||||
|
def restart_app(self, app_id, force=None):
|
||||||
|
"""Performs a rolling restart of all of the tasks.
|
||||||
|
|
||||||
|
:param app_id: the id of the application to restart
|
||||||
|
:type app_id: str
|
||||||
|
:param force: whether to override running deployments
|
||||||
|
:type force: bool
|
||||||
|
:returns: the deployment id and version; Error otherwise
|
||||||
|
:rtype: (dict, Error)
|
||||||
|
"""
|
||||||
|
|
||||||
|
app_id = normalize_app_id(app_id)
|
||||||
|
|
||||||
|
if not force:
|
||||||
|
params = None
|
||||||
|
else:
|
||||||
|
params = {'force': 'true'}
|
||||||
|
|
||||||
|
url = self._create_url('v2/apps{}/restart'.format(app_id), params)
|
||||||
|
|
||||||
|
logger.info('Posting %r', url)
|
||||||
|
response = requests.post(url)
|
||||||
|
logger.info('Got (%r): %r', response.status_code, response.json())
|
||||||
|
|
||||||
|
if _success(response.status_code):
|
||||||
|
return (response.json(), None)
|
||||||
|
else:
|
||||||
|
return (None, self._response_to_error(response))
|
||||||
|
|
||||||
|
|
||||||
class Error(errors.Error):
|
class Error(errors.Error):
|
||||||
""" Class for describing erros while talking to the Marathon server.
|
""" Class for describing errors while talking to the Marathon server.
|
||||||
|
|
||||||
:param message: Error message
|
:param message: Error message
|
||||||
:type message: str
|
:type message: str
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Usage:
|
|||||||
dcos app info
|
dcos app info
|
||||||
dcos app list
|
dcos app list
|
||||||
dcos app remove [--force] <app-id>
|
dcos app remove [--force] <app-id>
|
||||||
|
dcos app restart [--force] <app-id>
|
||||||
dcos app show [--app-version=<app-version>] <app-id>
|
dcos app show [--app-version=<app-version>] <app-id>
|
||||||
dcos app start [--force] <app-id> [<instances>]
|
dcos app start [--force] <app-id> [<instances>]
|
||||||
dcos app stop [--force] <app-id>
|
dcos app stop [--force] <app-id>
|
||||||
@@ -81,6 +82,9 @@ def main():
|
|||||||
if args['update']:
|
if args['update']:
|
||||||
return _update(args['<app-id>'], args['<properties>'], args['--force'])
|
return _update(args['<app-id>'], args['<properties>'], args['--force'])
|
||||||
|
|
||||||
|
if args['restart']:
|
||||||
|
return _restart(args['<app-id>'], args['--force'])
|
||||||
|
|
||||||
emitter.publish(options.make_generic_usage_error(__doc__))
|
emitter.publish(options.make_generic_usage_error(__doc__))
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
@@ -406,6 +410,43 @@ def _update(app_id, json_items, force):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _restart(app_id, force):
|
||||||
|
"""
|
||||||
|
:param app_id: the id of the application
|
||||||
|
:type app_id: str
|
||||||
|
:param force: whether to override running deployments
|
||||||
|
:type force: bool
|
||||||
|
:returns: process status
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
client = marathon.create_client(
|
||||||
|
config.load_from_path(
|
||||||
|
os.environ[constants.DCOS_CONFIG_ENV]))
|
||||||
|
|
||||||
|
desc, err = client.get_app(app_id)
|
||||||
|
if err is not None:
|
||||||
|
emitter.publish(err)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if desc['instances'] <= 0:
|
||||||
|
app_id = marathon.normalize_app_id(app_id)
|
||||||
|
emitter.publish(
|
||||||
|
'Unable to restart application {!r} because it is stopped'.format(
|
||||||
|
app_id,
|
||||||
|
desc['instances']))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
payload, err = client.restart_app(app_id, force)
|
||||||
|
if err is not None:
|
||||||
|
emitter.publish(err)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
emitter.publish('Created deployment {}'.format(payload['deploymentId']))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _update_from_stdin(app_id, force):
|
def _update_from_stdin(app_id, force):
|
||||||
"""
|
"""
|
||||||
:param app_id: the id of the application
|
:param app_id: the id of the application
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ def test_help():
|
|||||||
dcos app info
|
dcos app info
|
||||||
dcos app list
|
dcos app list
|
||||||
dcos app remove [--force] <app-id>
|
dcos app remove [--force] <app-id>
|
||||||
|
dcos app restart [--force] <app-id>
|
||||||
dcos app show [--app-version=<app-version>] <app-id>
|
dcos app show [--app-version=<app-version>] <app-id>
|
||||||
dcos app start [--force] <app-id> [<instances>]
|
dcos app start [--force] <app-id> [<instances>]
|
||||||
dcos app stop [--force] <app-id>
|
dcos app stop [--force] <app-id>
|
||||||
@@ -327,6 +328,45 @@ def test_update_app_from_stdin():
|
|||||||
_remove_app('zero-instance-app')
|
_remove_app('zero-instance-app')
|
||||||
|
|
||||||
|
|
||||||
|
def test_restarting_stopped_app():
|
||||||
|
_add_app('tests/data/marathon/zero_instance_sleep.json')
|
||||||
|
|
||||||
|
returncode, stdout, stderr = exec_command(
|
||||||
|
['dcos', 'app', 'restart', 'zero-instance-app'])
|
||||||
|
|
||||||
|
assert returncode == 1
|
||||||
|
assert stdout == (
|
||||||
|
b"Unable to restart application '/zero-instance-app' "
|
||||||
|
b"because it is stopped\n")
|
||||||
|
assert stderr == b''
|
||||||
|
|
||||||
|
_remove_app('zero-instance-app')
|
||||||
|
|
||||||
|
|
||||||
|
def test_restarting_missing_app():
|
||||||
|
returncode, stdout, stderr = exec_command(
|
||||||
|
['dcos', 'app', 'restart', 'missing-id'])
|
||||||
|
|
||||||
|
assert returncode == 1
|
||||||
|
assert stdout == b"Error: App '/missing-id' does not exist\n"
|
||||||
|
assert stderr == b''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(True, reason='We need to wait for the start to finish')
|
||||||
|
def test_restarting_app():
|
||||||
|
_add_app('tests/data/marathon/zero_instance_sleep.json')
|
||||||
|
_start_app('zero-instance-app')
|
||||||
|
|
||||||
|
returncode, stdout, stderr = exec_command(
|
||||||
|
['dcos', 'app', 'restart', 'zero-instance-app'])
|
||||||
|
|
||||||
|
assert returncode == 1
|
||||||
|
assert stdout.decode().startswith('Created deployment ')
|
||||||
|
assert stderr == b''
|
||||||
|
|
||||||
|
_remove_app('zero-instance-app')
|
||||||
|
|
||||||
|
|
||||||
def _list_apps(app_id=None):
|
def _list_apps(app_id=None):
|
||||||
returncode, stdout, stderr = exec_command(['dcos', 'app', 'list'])
|
returncode, stdout, stderr = exec_command(['dcos', 'app', 'list'])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user