diff --git a/.travis.yml b/.travis.yml index c227dfb..8d89ecf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ env: + - MARATHONVERSION: 1.9.109 - MARATHONVERSION: 1.6.322 - MARATHONVERSION: 1.4.11 - MARATHONVERSION: 1.3.0 diff --git a/README.md b/README.md index 592bb92..c109c83 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ This is a Python library for interfacing with [Marathon](https://github.com/meso #### Compatibility +* For Marathon 1.9.x, use at least 0.13.0 * For Marathon 1.6.x, use at least 0.10.0 * For Marathon 1.4.1, use at least 0.8.13 * For Marathon 1.1.1, use at least 0.8.1 diff --git a/marathon/client.py b/marathon/client.py index 8e61973..26c7914 100644 --- a/marathon/client.py +++ b/marathon/client.py @@ -13,6 +13,7 @@ import marathon from .models import MarathonApp, MarathonDeployment, MarathonGroup, MarathonInfo, MarathonTask, MarathonEndpoint, MarathonQueueItem from .exceptions import ConflictError, InternalServerError, NotFoundError, MarathonHttpError, MarathonError, NoResponseError +from .models.base import assert_valid_path from .models.events import EventFactory, MarathonEvent from .util import MarathonJsonEncoder, MarathonMinimalJsonEncoder @@ -167,8 +168,9 @@ def create_app(self, app_id, app, minimal=True): :returns: the created app (on success) :rtype: :class:`marathon.models.app.MarathonApp` or False """ - app.id = app_id + app.id = assert_valid_path(app_id) data = app.to_json(minimal=minimal) + marathon.log.debug('create app JSON sent: {}'.format(data)) response = self._do_request('POST', '/v2/apps', data=data) if response.status_code == 201: return self._parse_response(response, MarathonApp) diff --git a/marathon/models/app.py b/marathon/models/app.py index 00a3d57..e290fd9 100644 --- a/marathon/models/app.py +++ b/marathon/models/app.py @@ -38,6 +38,7 @@ class MarathonApp(MarathonResource): :param health_checks: health checks :type health_checks: list[:class:`marathon.models.MarathonHealthCheck`] or list[dict] :param str id: app id + :param str role: mesos role :param int instances: instances :param last_task_failure: last task failure :type last_task_failure: :class:`marathon.models.app.MarathonTaskFailure` or dict @@ -75,7 +76,7 @@ class MarathonApp(MarathonResource): 'args', 'backoff_factor', 'backoff_seconds', 'cmd', 'constraints', 'container', 'cpus', 'dependencies', 'disk', 'env', 'executor', 'gpus', 'health_checks', 'instances', 'kill_selection', 'labels', 'max_launch_delay_seconds', 'mem', 'ports', 'require_ports', 'store_urls', 'task_rate_limit', 'upgrade_strategy', 'unreachable_strategy', - 'uris', 'user', 'version' + 'uris', 'user', 'version', 'role' ] """List of attributes which may be updated/changed after app creation""" @@ -90,7 +91,7 @@ class MarathonApp(MarathonResource): def __init__(self, accepted_resource_roles=None, args=None, backoff_factor=None, backoff_seconds=None, cmd=None, constraints=None, container=None, cpus=None, dependencies=None, deployments=None, disk=None, env=None, - executor=None, health_checks=None, id=None, instances=None, kill_selection=None, labels=None, + executor=None, health_checks=None, id=None, role=None, instances=None, kill_selection=None, labels=None, last_task_failure=None, max_launch_delay_seconds=None, mem=None, ports=None, require_ports=None, store_urls=None, task_rate_limit=None, tasks=None, tasks_running=None, tasks_staged=None, tasks_healthy=None, task_kill_grace_period_seconds=None, tasks_unhealthy=None, upgrade_strategy=None, @@ -131,6 +132,7 @@ def __init__(self, accepted_resource_roles=None, args=None, backoff_factor=None, for hc in (health_checks or []) ] self.id = assert_valid_path(id) + self.role = role self.instances = instances if kill_selection and kill_selection not in self.KILL_SELECTIONS: raise InvalidChoiceError( diff --git a/marathon/models/deployment.py b/marathon/models/deployment.py index 97e73ec..d7ac7cd 100644 --- a/marathon/models/deployment.py +++ b/marathon/models/deployment.py @@ -1,4 +1,4 @@ -from .base import MarathonObject, MarathonResource +from .base import MarathonObject, MarathonResource, assert_valid_path class MarathonDeployment(MarathonResource): @@ -60,8 +60,8 @@ class MarathonDeploymentAction(MarathonObject): def __init__(self, action=None, app=None, apps=None, type=None, readiness_check_results=None, pod=None): self.action = action - self.app = app - self.apps = apps + self.app = assert_valid_path(app) + self.apps = assert_valid_path(apps) self.pod = pod self.type = type # TODO: Remove builtin shadow self.readiness_check_results = readiness_check_results # TODO: The docs say this is called just "readinessChecks?" diff --git a/marathon/models/info.py b/marathon/models/info.py index 5ca62d4..68622a3 100644 --- a/marathon/models/info.py +++ b/marathon/models/info.py @@ -64,10 +64,12 @@ class MarathonConfig(MarathonObject): :param int leader_proxy_read_timeout_ms: :param int local_port_min: :param int local_port_max: + :param bool maintenance_mode: :param str master: :param str mesos_leader_ui_url: :param str mesos_role: :param str mesos_user: + :param str new_group_enforce_role: :param str webui_url: :param int reconciliation_initial_delay: :param int reconciliation_interval: @@ -99,12 +101,12 @@ class MarathonConfig(MarathonObject): def __init__(self, checkpoint=None, executor=None, failover_timeout=None, framework_name=None, ha=None, hostname=None, leader_proxy_connection_timeout_ms=None, leader_proxy_read_timeout_ms=None, - local_port_min=None, local_port_max=None, master=None, mesos_leader_ui_url=None, mesos_role=None, mesos_user=None, - webui_url=None, reconciliation_initial_delay=None, reconciliation_interval=None, - task_launch_timeout=None, marathon_store_timeout=None, task_reservation_timeout=None, features=None, - access_control_allow_origin=None, decline_offer_duration=None, - default_network_name=None, env_vars_prefix=None, - launch_token=None, launch_token_refresh_interval=None, + local_port_min=None, local_port_max=None, maintenance_mode=None, master=None, mesos_leader_ui_url=None, + mesos_role=None, mesos_user=None, new_group_enforce_role=None, webui_url=None, + reconciliation_initial_delay=None, reconciliation_interval=None, task_launch_timeout=None, + marathon_store_timeout=None, task_reservation_timeout=None, features=None, + access_control_allow_origin=None, decline_offer_duration=None, default_network_name=None, + env_vars_prefix=None, launch_token=None, launch_token_refresh_interval=None, max_instances_per_offer=None, mesos_bridge_name=None, mesos_heartbeat_failure_threshold=None, mesos_heartbeat_interval=None, min_revive_offers_interval=None, @@ -124,10 +126,12 @@ def __init__(self, checkpoint=None, executor=None, failover_timeout=None, framew self.hostname = hostname self.local_port_min = local_port_min self.local_port_max = local_port_max + self.maintenance_mode = maintenance_mode self.master = master self.mesos_leader_ui_url = mesos_leader_ui_url self.mesos_role = mesos_role self.mesos_user = mesos_user + self.new_group_enforce_role = new_group_enforce_role self.webui_url = webui_url self.reconciliation_initial_delay = reconciliation_initial_delay self.reconciliation_interval = reconciliation_interval diff --git a/marathon/models/task.py b/marathon/models/task.py index e049748..0348c6a 100644 --- a/marathon/models/task.py +++ b/marathon/models/task.py @@ -24,13 +24,15 @@ class MarathonTask(MarathonResource): :param region: fault domain region support in DCOS EE :type zone: str :param zone: fault domain zone support in DCOS EE + :type role: str + :param role: mesos role """ DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ' def __init__(self, app_id=None, health_check_results=None, host=None, id=None, ports=None, service_ports=None, slave_id=None, staged_at=None, started_at=None, version=None, ip_addresses=[], state=None, local_volumes=None, - region=None, zone=None): + region=None, zone=None, role=None): self.app_id = app_id self.health_check_results = health_check_results or [] self.health_check_results = [ @@ -54,6 +56,7 @@ def __init__(self, app_id=None, health_check_results=None, host=None, id=None, p self.local_volumes = local_volumes or [] self.region = region self.zone = zone + self.role = role class MarathonIpAddress(MarathonObject):