Remove Marathon AppDefinition checks
This commit also updates the tests to pass against the latest universe
This commit is contained in:
committed by
José Armando García Sancio
parent
b373072811
commit
ac12d45a8b
@@ -1,311 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"app": {
|
||||
"additionalProperties": false,
|
||||
"not": {
|
||||
"allOf": [
|
||||
{
|
||||
"required": [
|
||||
"cmd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"args"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"acceptedResourceRoles": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"args": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"backoffFactor": {
|
||||
"minimum": 1.0,
|
||||
"type": "number"
|
||||
},
|
||||
"backoffSeconds": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"cmd": {
|
||||
"minLength": 1,
|
||||
"type": "string"
|
||||
},
|
||||
"constraints": {},
|
||||
"container": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"docker": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"forcePullImage": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"image": {
|
||||
"type": "string"
|
||||
},
|
||||
"network": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"key",
|
||||
"value"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"portMappings": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"hostPort": {
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
},
|
||||
"servicePort": {
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"privileged": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"volumes": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"containerPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"cpus": {
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"dependencies": {
|
||||
"items": {
|
||||
"pattern": "^(\\/?((\\.{2})|([a-z0-9\\-]*))($|\\/))*$",
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"disk": {
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"env": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"executor": {
|
||||
"pattern": "^(|\\/\\/cmd|\\/?[^\\/]+(\\/[^\\/]+)*)$",
|
||||
"type": "string"
|
||||
},
|
||||
"healthChecks": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"gracePeriodSeconds": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"ignoreHttp1xx": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"intervalSeconds": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"maxConsecutiveFailures": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"portIndex": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeoutSeconds": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"id": {
|
||||
"pattern": "^(\\/?((\\.{2})|([a-z0-9][a-z0-9\\-]*[a-z0-9]+)|([a-z0-9]*))($|\\/))*$",
|
||||
"type": "string"
|
||||
},
|
||||
"instances": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"labels": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"maxLaunchDelaySeconds": {
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"mem": {
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"ports": {
|
||||
"items": {
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"requirePorts": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"storeUrls": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"upgradeStrategy": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"maximumOverCapacity": {
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0,
|
||||
"type": "number"
|
||||
},
|
||||
"minimumHealthCapacity": {
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0,
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"uris": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"apps": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/app"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"dependencies": {
|
||||
"$ref": "#/definitions/app/properties/dependencies"
|
||||
},
|
||||
"groups": {
|
||||
"items": {
|
||||
"$ref": "#"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"id": {
|
||||
"$ref": "#/definitions/app/properties/id"
|
||||
},
|
||||
"version": {
|
||||
"$ref": "#/definitions/app/properties/version"
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
@@ -357,14 +357,6 @@ def _add(app_resource):
|
||||
# Add application to marathon
|
||||
client = marathon.create_client()
|
||||
|
||||
schema = client.get_app_schema()
|
||||
if schema is None:
|
||||
schema = _app_schema()
|
||||
|
||||
errs = util.validate_json(application_resource, schema)
|
||||
if errs:
|
||||
raise DCOSException(util.list_to_err(errs))
|
||||
|
||||
# Check that the application doesn't exist
|
||||
app_id = client.normalize_app_id(application_resource['id'])
|
||||
|
||||
@@ -427,11 +419,6 @@ def _group_add(group_resource):
|
||||
"""
|
||||
|
||||
group_resource = _get_resource(group_resource)
|
||||
schema = _data_schema()
|
||||
|
||||
errs = util.validate_json(group_resource, schema)
|
||||
if errs:
|
||||
raise DCOSException(util.list_to_err(errs))
|
||||
|
||||
client = marathon.create_client()
|
||||
|
||||
@@ -536,13 +523,10 @@ def _group_update(group_id, properties, force):
|
||||
client = marathon.create_client()
|
||||
|
||||
# Ensure that the group exists
|
||||
current_group = client.get_group(group_id)
|
||||
client.get_group(group_id)
|
||||
|
||||
schema = _data_schema()
|
||||
group_resource = _parse_properties(properties, schema)
|
||||
_validate_update(current_group, group_resource, schema)
|
||||
|
||||
deployment = client.update_group(group_id, group_resource, force)
|
||||
properties = _parse_properties(properties)
|
||||
deployment = client.update_group(group_id, properties, force)
|
||||
|
||||
emitter.publish('Created deployment {}'.format(deployment))
|
||||
return 0
|
||||
@@ -641,13 +625,10 @@ def _update(app_id, properties, force):
|
||||
client = marathon.create_client()
|
||||
|
||||
# Ensure that the application exists
|
||||
current_app = client.get_app(app_id)
|
||||
client.get_app(app_id)
|
||||
|
||||
schema = _app_schema()
|
||||
app_resource = _parse_properties(properties, schema)
|
||||
_validate_update(current_app, app_resource, schema)
|
||||
|
||||
deployment = client.update_app(app_id, app_resource, force)
|
||||
properties = _parse_properties(properties)
|
||||
deployment = client.update_app(app_id, properties, force)
|
||||
|
||||
emitter.publish('Created deployment {}'.format(deployment))
|
||||
return 0
|
||||
@@ -672,68 +653,10 @@ def _group_scale(group_id, scale_factor, force):
|
||||
return 0
|
||||
|
||||
|
||||
def _validate_update(current_resource, properties, schema):
|
||||
"""
|
||||
Validate resource ("app" or "group") update
|
||||
|
||||
:param current_resource: Marathon app definition
|
||||
:type current_resource: dict
|
||||
:param properties: resource JSON
|
||||
:type properties: dict
|
||||
:param schema: JSON schema used to verify properties
|
||||
:type schema: dict
|
||||
:rtype: None
|
||||
"""
|
||||
updated_resource = _clean_up_resource_definition(current_resource.copy())
|
||||
updated_resource.update(properties)
|
||||
|
||||
errs = util.validate_json(updated_resource, schema)
|
||||
if errs:
|
||||
raise DCOSException(util.list_to_err(errs))
|
||||
|
||||
|
||||
def _clean_up_resource_definition(properties):
|
||||
"""
|
||||
Remove non user-specified properties and nulls from resource definition.
|
||||
We remove fields that marathon adds because they aren't in the json-schema
|
||||
because a user should not specity them. When we do a `get` to see the
|
||||
current resource, we may see these fields, but leaving them will cause us
|
||||
to unnecessarily fail the schema validation.
|
||||
|
||||
:param properties: resource JSON
|
||||
:type properties: dict
|
||||
:returns: resource JSON
|
||||
:rtype: dict
|
||||
"""
|
||||
clean_properties = {}
|
||||
ignore_properties = ["deployments", "lastTaskFailure", "tasks",
|
||||
"tasksRunning", "tasksHealthy", "tasksUnhealthy",
|
||||
"tasksStaged"]
|
||||
for k, v in properties.items():
|
||||
if v is not None and k not in ignore_properties:
|
||||
# iterate through dict/list(s) to check all properties
|
||||
if isinstance(v, list):
|
||||
v = [value for value in v if value]
|
||||
clean_properties[k] = [
|
||||
_clean_up_resource_definition(elem)
|
||||
if isinstance(elem, dict)
|
||||
else elem
|
||||
for elem in v
|
||||
]
|
||||
elif isinstance(v, dict):
|
||||
clean_properties[k] = _clean_up_resource_definition(v)
|
||||
else:
|
||||
clean_properties[k] = v
|
||||
|
||||
return clean_properties
|
||||
|
||||
|
||||
def _parse_properties(properties, schema):
|
||||
def _parse_properties(properties):
|
||||
"""
|
||||
:param properties: JSON items in the form key=value
|
||||
:type properties: [str]
|
||||
:param schema: The JSON schema used to verify properties
|
||||
:type schema: dict
|
||||
:returns: resource JSON
|
||||
:rtype: dict
|
||||
"""
|
||||
@@ -751,7 +674,7 @@ def _parse_properties(properties, schema):
|
||||
|
||||
resource_json = {}
|
||||
for prop in properties:
|
||||
key, value = jsonitem.parse_json_item(prop, schema)
|
||||
key, value = jsonitem.parse_json_item(prop, None)
|
||||
|
||||
key = jsonitem.clean_value(key)
|
||||
if key in resource_json:
|
||||
@@ -759,7 +682,6 @@ def _parse_properties(properties, schema):
|
||||
'Key {!r} was specified more than once'.format(key))
|
||||
|
||||
resource_json[key] = value
|
||||
|
||||
return resource_json
|
||||
|
||||
|
||||
@@ -990,22 +912,3 @@ def _cli_config_schema():
|
||||
pkg_resources.resource_string(
|
||||
'dcoscli',
|
||||
'data/config-schema/marathon.json').decode('utf-8'))
|
||||
|
||||
|
||||
def _data_schema():
|
||||
"""
|
||||
:returns: schema for marathon data
|
||||
:rtype: dict
|
||||
"""
|
||||
return json.loads(
|
||||
pkg_resources.resource_string(
|
||||
'dcoscli',
|
||||
'data/marathon-group-schema.json').decode('utf-8'))
|
||||
|
||||
|
||||
def _app_schema():
|
||||
"""
|
||||
:returns: schema for apps
|
||||
:rtype: dict
|
||||
"""
|
||||
return _data_schema()['definitions']['app']
|
||||
|
||||
@@ -306,7 +306,7 @@ def _log_marathon(follow, lines, ssh_config_file):
|
||||
leader_ip = marathon.create_client().get_leader().split(':')[0]
|
||||
|
||||
cmd = ("ssh {0}core@{1} " +
|
||||
"journalctl {2}-u marathon").format(
|
||||
"journalctl {2}-u dcos-marathon").format(
|
||||
ssh_options,
|
||||
leader_ip,
|
||||
journalctl_args)
|
||||
|
||||
@@ -5,5 +5,5 @@ timeout = 5
|
||||
ssl_verify = "false"
|
||||
dcos_url = "http://dcos.snakeoil.mesosphere.com"
|
||||
[package]
|
||||
sources = [ "https://github.com/mesosphere/universe/archive/cli-tests.zip",]
|
||||
sources = [ "https://github.com/mesosphere/universe/archive/cli-test-2.zip",]
|
||||
cache = "tmp/cache"
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"backoffFactor": 1.15,
|
||||
"backoffSeconds": 1,
|
||||
"maxLaunchDelaySeconds": 3600,
|
||||
"cmd": "python3 -m http.server 8080",
|
||||
"constraints": [],
|
||||
"container": {
|
||||
"docker": {
|
||||
"image": "python:3",
|
||||
"network": "BRIDGE",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"hostPort": 0,
|
||||
"servicePort": 9000,
|
||||
"protocol": "tcp"
|
||||
},
|
||||
{
|
||||
"containerPort": 161,
|
||||
"hostPort": 0,
|
||||
"protocol": "udp"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "DOCKER",
|
||||
"volumes": []
|
||||
},
|
||||
"cpus": 0.5,
|
||||
"dependencies": [],
|
||||
"disk": 0.0,
|
||||
"env": {},
|
||||
"executor": "",
|
||||
"healthChecks": [
|
||||
{
|
||||
"gracePeriodSeconds": 5,
|
||||
"intervalSeconds": 20,
|
||||
"maxConsecutiveFailures": 3,
|
||||
"path": "/",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 20
|
||||
}
|
||||
],
|
||||
"id": "/bridged-webapp",
|
||||
"instances": 2,
|
||||
"mem": 64.0,
|
||||
"ports": [
|
||||
10000,
|
||||
10001
|
||||
],
|
||||
"requirePorts": false,
|
||||
"storeUrls": [],
|
||||
"upgradeStrategy": {
|
||||
"minimumHealthCapacity": 1.0
|
||||
},
|
||||
"uris": [],
|
||||
"version": "2014-09-25T02:26:59.256Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"args": null,
|
||||
"backoffFactor": 1.15,
|
||||
"backoffSeconds": 1,
|
||||
"maxLaunchDelaySeconds": 3600,
|
||||
"cmd": "python3 -m http.server 8080",
|
||||
"constraints": [],
|
||||
"container": {
|
||||
"docker": {
|
||||
"image": "python:3",
|
||||
"network": "BRIDGE",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"hostPort": 0,
|
||||
"servicePort": 9000,
|
||||
"protocol": "tcp"
|
||||
},
|
||||
{
|
||||
"containerPort": 161,
|
||||
"hostPort": 0,
|
||||
"protocol": "udp"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "DOCKER",
|
||||
"volumes": []
|
||||
},
|
||||
"cpus": 0.5,
|
||||
"dependencies": [],
|
||||
"deployments": [],
|
||||
"disk": 0.0,
|
||||
"env": {},
|
||||
"executor": "",
|
||||
"healthChecks": [
|
||||
{
|
||||
"command": null,
|
||||
"gracePeriodSeconds": 5,
|
||||
"intervalSeconds": 20,
|
||||
"maxConsecutiveFailures": 3,
|
||||
"path": "/",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 20
|
||||
}
|
||||
],
|
||||
"id": "/bridged-webapp",
|
||||
"instances": 2,
|
||||
"mem": 64.0,
|
||||
"ports": [
|
||||
10000,
|
||||
10001
|
||||
],
|
||||
"requirePorts": false,
|
||||
"storeUrls": [],
|
||||
"tasksRunning": 2,
|
||||
"tasksHealthy": 2,
|
||||
"tasksUnhealthy": 0,
|
||||
"tasksStaged": 0,
|
||||
"upgradeStrategy": {
|
||||
"minimumHealthCapacity": 1.0
|
||||
},
|
||||
"uris": [],
|
||||
"user": null,
|
||||
"version": "2014-09-25T02:26:59.256Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"id": "sleep-two-instances",
|
||||
"id": "sleep-many-instances",
|
||||
"cmd": "sleep 1000",
|
||||
"cpus": 0.1,
|
||||
"mem": 16,
|
||||
"instances": 2,
|
||||
"instances": 10,
|
||||
"labels": {
|
||||
"PACKAGE_ID": "test-app",
|
||||
"PACKAGE_VERSION": "1.2.3"
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"id": "notgood",
|
||||
"apps": [
|
||||
{
|
||||
"id": "hi",
|
||||
"cmd": "sleep 0",
|
||||
"badtype": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"id": "bad-group"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"fakeapp": [
|
||||
{
|
||||
"cmds": "sleep 0",
|
||||
"id": "hi",
|
||||
"instances": 0
|
||||
}
|
||||
],
|
||||
"id": "notgood"
|
||||
}
|
||||
],
|
||||
"id": "bad-group"
|
||||
}
|
||||
@@ -1,20 +1,80 @@
|
||||
{
|
||||
"pip": [
|
||||
"dcos<1.0",
|
||||
"git+https://github.com/mesosphere/dcos-helloworld.git#dcos-helloworld=0.1.0"
|
||||
"dcos==0.1.13",
|
||||
"git+https://github.com/mesosphere/dcos-cassandra.git#dcos-cassandra=0.1.0"
|
||||
]
|
||||
}
|
||||
{
|
||||
"id": "helloworld",
|
||||
"cpus": 1.0,
|
||||
"mem": 512,
|
||||
"instances": 1,
|
||||
"cmd": "python3 -m http.server {{port}}",
|
||||
"container": {
|
||||
"type": "DOCKER",
|
||||
"docker": {
|
||||
"image": "python:3",
|
||||
"network": "HOST"
|
||||
"id": "/cassandra/{{cassandra.cluster-name}}",
|
||||
"cmd": "$(pwd)/jre*/bin/java $JAVA_OPTS -classpath cassandra-mesos-framework.jar io.mesosphere.mesos.frameworks.cassandra.framework.Main",
|
||||
"instances": {{cassandra.framework.instances}},
|
||||
"cpus": {{cassandra.framework.cpus}},
|
||||
"mem": {{cassandra.framework.mem}},
|
||||
"ports": [
|
||||
0
|
||||
],
|
||||
"uris": [
|
||||
"https://downloads.mesosphere.io/cassandra-mesos/artifacts/0.2.0-1/cassandra-mesos-0.2.0-1.tar.gz",
|
||||
"https://downloads.mesosphere.io/java/jre-7u76-linux-x64.tar.gz"
|
||||
],
|
||||
"healthChecks": [
|
||||
{
|
||||
"gracePeriodSeconds": 120,
|
||||
"intervalSeconds": 15,
|
||||
"maxConsecutiveFailures": 0,
|
||||
"path": "/health/cluster",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 5
|
||||
},
|
||||
{
|
||||
"gracePeriodSeconds": 120,
|
||||
"intervalSeconds": 30,
|
||||
"maxConsecutiveFailures": 3,
|
||||
"path": "/health/process",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 5
|
||||
}
|
||||
],
|
||||
"labels": {
|
||||
"DCOS_PACKAGE_FRAMEWORK_NAME": "cassandra.{{cassandra.cluster-name}}"
|
||||
},
|
||||
"env": {
|
||||
"MESOS_ZK": "{{mesos.master}}"
|
||||
,"JAVA_OPTS": "-Xms256m -Xmx256m"
|
||||
,"CASSANDRA_CLUSTER_NAME": "{{cassandra.cluster-name}}"
|
||||
,"CASSANDRA_NODE_COUNT": "{{cassandra.node-count}}"
|
||||
,"CASSANDRA_SEED_COUNT": "{{cassandra.seed-count}}"
|
||||
,"CASSANDRA_RESOURCE_CPU_CORES": "{{cassandra.resources.cpus}}"
|
||||
,"CASSANDRA_RESOURCE_MEM_MB": "{{cassandra.resources.mem}}"
|
||||
,"CASSANDRA_RESOURCE_DISK_MB": "{{cassandra.resources.disk}}"
|
||||
,"CASSANDRA_FAILOVER_TIMEOUT_SECONDS": "{{cassandra.framework.failover-timeout-seconds}}"
|
||||
,"CASSANDRA_DATA_DIRECTORY": "{{cassandra.data-directory}}"
|
||||
,"CASSANDRA_HEALTH_CHECK_INTERVAL_SECONDS": "{{cassandra.health-check-interval-seconds}}"
|
||||
,"CASSANDRA_ZK_TIMEOUT_MS": "{{cassandra.zk-timeout-ms}}"
|
||||
,"CASSANDRA_BOOTSTRAP_GRACE_TIME_SECONDS": "{{cassandra.bootstrap-grace-time-seconds}}"
|
||||
,"CASSANDRA_FRAMEWORK_MESOS_ROLE": "{{cassandra.framework.role}}"
|
||||
,"CASSANDRA_DEFAULT_DC": "{{cassandra.dc.default-dc}}"
|
||||
,"CASSANDRA_DEFAULT_RACK": "{{cassandra.dc.default-rack}}"
|
||||
,"MESOS_AUTHENTICATE": "{{cassandra.framework.authentication.enabled}}"
|
||||
{{#cassandra.dc.external-dcs}}
|
||||
,"CASSANDRA_EXTERNAL_DC_{{name}}": "{{url}}"
|
||||
{{/cassandra.dc.external-dcs}}
|
||||
{{#cassandra.zk}} {{! if the full cassandra zk url has been specified use it }}
|
||||
,"CASSANDRA_ZK": "{{cassandra.zk}}"
|
||||
{{/cassandra.zk}}
|
||||
{{^cassandra.zk}} {{! else, create a url based on convention and cluster name }}
|
||||
,"CASSANDRA_ZK": "zk://master.mesos:2181/cassandra-mesos/{{cassandra.cluster-name}}"
|
||||
{{/cassandra.zk}}
|
||||
{{#cassandra.resource.heap-mb}}
|
||||
,"CASSANDRA_RESOURCE_HEAP_MB": "{{cassandra.resource.heap-mb}}"
|
||||
{{/cassandra.resource.heap-mb}}
|
||||
{{#cassandra.framework.authentication.principal}}
|
||||
,"DEFAULT_PRINCIPAL": "{{cassandra.framework.authentication.principal}}"
|
||||
{{/cassandra.framework.authentication.principal}}
|
||||
{{#cassandra.framework.authentication.secret}}
|
||||
,"DEFAULT_SECRET": "{{cassandra.framework.authentication.secret}}"
|
||||
{{/cassandra.framework.authentication.secret}}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"cmd": "LIBPROCESS_PORT=$PORT1 && ./bin/start --master zk://master.mesos:2181/mesos --checkpoint --failover_timeout 604800 --framework_name marathon-user --ha --zk zk://localhost:2181/mesos/marathon-user --http_port $PORT0 ",
|
||||
"cmd": "LIBPROCESS_PORT=$PORT1 && ./bin/start --master zk://master.mesos:2181/mesos --checkpoint --decline_offer_duration 5000 --http_port $PORT0 --event_stream_max_outstanding_messages 50 --failover_timeout 604800 --framework_name marathon-user --ha --leader_proxy_connection_timeout 5000 --leader_proxy_read_timeout 10000 --local_port_max 20000 --local_port_min 10000 --marathon_store_timeout 2000 --max_tasks_per_offer 1 --max_tasks_per_offer_cycle 1000 --min_revive_offers_interval 5000 --revive_offers_for_new_apps --scale_apps_initial_delay 15000 --scale_apps_interval 300000 --zk_session_timeout 1800000 --zk zk://localhost:2181/mesos --mesos_leader_ui_url /mesos --zk_compression --zk_compression_threshold 65536 ",
|
||||
"constraints": [
|
||||
[
|
||||
"hostname",
|
||||
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"container": {
|
||||
"docker": {
|
||||
"image": "mesosphere/marathon:v0.9.0",
|
||||
"image": "mesosphere/marathon:v0.11.1",
|
||||
"network": "HOST"
|
||||
},
|
||||
"type": "DOCKER"
|
||||
@@ -17,17 +17,28 @@
|
||||
"env": {
|
||||
"JVM_OPTS": "-Xms256m -Xmx768m"
|
||||
},
|
||||
"healthChecks": [
|
||||
{
|
||||
"gracePeriodSeconds": 120,
|
||||
"intervalSeconds": 10,
|
||||
"maxConsecutiveFailures": 3,
|
||||
"path": "/v2/info",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 5
|
||||
}
|
||||
],
|
||||
"id": "marathon-user",
|
||||
"instances": 1,
|
||||
"labels": {
|
||||
"DCOS_PACKAGE_FRAMEWORK_NAME": "marathon-user",
|
||||
"DCOS_PACKAGE_IS_FRAMEWORK": "true",
|
||||
"DCOS_PACKAGE_METADATA": "eyJkZXNjcmlwdGlvbiI6ICJBIGNsdXN0ZXItd2lkZSBpbml0IGFuZCBjb250cm9sIHN5c3RlbSBmb3Igc2VydmljZXMgaW4gY2dyb3VwcyBvciBEb2NrZXIgY29udGFpbmVycy4iLCAiZnJhbWV3b3JrIjogdHJ1ZSwgImltYWdlcyI6IHsiaWNvbi1sYXJnZSI6ICJodHRwczovL2Rvd25sb2Fkcy5tZXNvc3BoZXJlLmlvL21hcmF0aG9uL2Fzc2V0cy9pY29uLXNlcnZpY2UtbWFyYXRob24tbGFyZ2UucG5nIiwgImljb24tbWVkaXVtIjogImh0dHBzOi8vZG93bmxvYWRzLm1lc29zcGhlcmUuaW8vbWFyYXRob24vYXNzZXRzL2ljb24tc2VydmljZS1tYXJhdGhvbi1tZWRpdW0ucG5nIiwgImljb24tc21hbGwiOiAiaHR0cHM6Ly9kb3dubG9hZHMubWVzb3NwaGVyZS5pby9tYXJhdGhvbi9hc3NldHMvaWNvbi1zZXJ2aWNlLW1hcmF0aG9uLXNtYWxsLnBuZyJ9LCAibGljZW5zZXMiOiBbeyJuYW1lIjogIkFwYWNoZSBMaWNlbnNlIFZlcnNpb24gMi4wIiwgInVybCI6ICJodHRwczovL2dpdGh1Yi5jb20vbWVzb3NwaGVyZS9tYXJhdGhvbi9ibG9iL21hc3Rlci9MSUNFTlNFIn1dLCAibWFpbnRhaW5lciI6ICJzdXBwb3J0QG1lc29zcGhlcmUuaW8iLCAibmFtZSI6ICJtYXJhdGhvbiIsICJwb3N0SW5zdGFsbE5vdGVzIjogIk1hcmF0aG9uIERDT1MgU2VydmljZSBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgaW5zdGFsbGVkIVxuXG5cdERvY3VtZW50YXRpb246IGh0dHBzOi8vbWVzb3NwaGVyZS5naXRodWIuaW8vbWFyYXRob25cblx0SXNzdWVzOiBodHRwczovZ2l0aHViLmNvbS9tZXNvc3BoZXJlL21hcmF0aG9uL2lzc3Vlc1xuIiwgInBvc3RVbmluc3RhbGxOb3RlcyI6ICJUaGUgTWFyYXRob24gRENPUyBTZXJ2aWNlIGhhcyBiZWVuIHVuaW5zdGFsbGVkIGFuZCB3aWxsIG5vIGxvbmdlciBydW4uXG5QbGVhc2UgZm9sbG93IHRoZSBpbnN0cnVjdGlvbnMgYXQgaHR0cDovL2RvY3MubWVzb3NwaGVyZS5jb20vc2VydmljZXMvbWFyYXRob24vI3VuaW5zdGFsbCB0byBjbGVhbiB1cCBhbnkgcGVyc2lzdGVkIHN0YXRlIiwgInByZUluc3RhbGxOb3RlcyI6ICJXZSByZWNvbW1lbmQgYSBtaW5pbXVtIG9mIG9uZSBub2RlIHdpdGggYXQgbGVhc3QgMiBDUFUncyBhbmQgMUdCIG9mIFJBTSBhdmFpbGFibGUgZm9yIHRoZSBNYXJhdGhvbiBTZXJ2aWNlLiIsICJzY20iOiAiaHR0cHM6Ly9naXRodWIuY29tL21lc29zcGhlcmUvbWFyYXRob24uZ2l0IiwgInRhZ3MiOiBbIm1lc29zcGhlcmUiLCAiZnJhbWV3b3JrIl0sICJ2ZXJzaW9uIjogIjAuOS4wIn0=",
|
||||
"DCOS_PACKAGE_METADATA": "eyJkZXNjcmlwdGlvbiI6ICJBIGNsdXN0ZXItd2lkZSBpbml0IGFuZCBjb250cm9sIHN5c3RlbSBmb3Igc2VydmljZXMgaW4gY2dyb3VwcyBvciBEb2NrZXIgY29udGFpbmVycy4iLCAiZnJhbWV3b3JrIjogdHJ1ZSwgImltYWdlcyI6IHsiaWNvbi1sYXJnZSI6ICJodHRwczovL2Rvd25sb2Fkcy5tZXNvc3BoZXJlLmlvL21hcmF0aG9uL2Fzc2V0cy9pY29uLXNlcnZpY2UtbWFyYXRob24tbGFyZ2UucG5nIiwgImljb24tbWVkaXVtIjogImh0dHBzOi8vZG93bmxvYWRzLm1lc29zcGhlcmUuaW8vbWFyYXRob24vYXNzZXRzL2ljb24tc2VydmljZS1tYXJhdGhvbi1tZWRpdW0ucG5nIiwgImljb24tc21hbGwiOiAiaHR0cHM6Ly9kb3dubG9hZHMubWVzb3NwaGVyZS5pby9tYXJhdGhvbi9hc3NldHMvaWNvbi1zZXJ2aWNlLW1hcmF0aG9uLXNtYWxsLnBuZyJ9LCAibGljZW5zZXMiOiBbeyJuYW1lIjogIkFwYWNoZSBMaWNlbnNlIFZlcnNpb24gMi4wIiwgInVybCI6ICJodHRwczovL2dpdGh1Yi5jb20vbWVzb3NwaGVyZS9tYXJhdGhvbi9ibG9iL21hc3Rlci9MSUNFTlNFIn1dLCAibWFpbnRhaW5lciI6ICJzdXBwb3J0QG1lc29zcGhlcmUuaW8iLCAibmFtZSI6ICJtYXJhdGhvbiIsICJwb3N0SW5zdGFsbE5vdGVzIjogIk1hcmF0aG9uIERDT1MgU2VydmljZSBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgaW5zdGFsbGVkIVxuXG5cdERvY3VtZW50YXRpb246IGh0dHBzOi8vbWVzb3NwaGVyZS5naXRodWIuaW8vbWFyYXRob25cblx0SXNzdWVzOiBodHRwczovZ2l0aHViLmNvbS9tZXNvc3BoZXJlL21hcmF0aG9uL2lzc3Vlc1xuIiwgInBvc3RVbmluc3RhbGxOb3RlcyI6ICJUaGUgTWFyYXRob24gRENPUyBTZXJ2aWNlIGhhcyBiZWVuIHVuaW5zdGFsbGVkIGFuZCB3aWxsIG5vIGxvbmdlciBydW4uXG5QbGVhc2UgZm9sbG93IHRoZSBpbnN0cnVjdGlvbnMgYXQgaHR0cDovL2RvY3MubWVzb3NwaGVyZS5jb20vc2VydmljZXMvbWFyYXRob24vI3VuaW5zdGFsbCB0byBjbGVhbiB1cCBhbnkgcGVyc2lzdGVkIHN0YXRlIiwgInByZUluc3RhbGxOb3RlcyI6ICJXZSByZWNvbW1lbmQgYSBtaW5pbXVtIG9mIG9uZSBub2RlIHdpdGggYXQgbGVhc3QgMiBDUFUncyBhbmQgMUdCIG9mIFJBTSBhdmFpbGFibGUgZm9yIHRoZSBNYXJhdGhvbiBTZXJ2aWNlLiIsICJzY20iOiAiaHR0cHM6Ly9naXRodWIuY29tL21lc29zcGhlcmUvbWFyYXRob24uZ2l0IiwgInRhZ3MiOiBbImluaXQiLCAibG9uZy1ydW5uaW5nIl0sICJ2ZXJzaW9uIjogIjAuMTEuMSJ9",
|
||||
"DCOS_PACKAGE_NAME": "marathon",
|
||||
"DCOS_PACKAGE_REGISTRY_VERSION": "1.0.0-rc1",
|
||||
"DCOS_PACKAGE_RELEASE": "2",
|
||||
"DCOS_PACKAGE_SOURCE": "https://github.com/mesosphere/universe/archive/cli-tests.zip",
|
||||
"DCOS_PACKAGE_VERSION": "0.9.0"
|
||||
"DCOS_PACKAGE_RELEASE": "6",
|
||||
"DCOS_PACKAGE_SOURCE": "https://github.com/mesosphere/universe/archive/cli-test-2.zip",
|
||||
"DCOS_PACKAGE_VERSION": "0.11.1"
|
||||
},
|
||||
"mem": 1024.0,
|
||||
"ports": [
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"pip": [
|
||||
"dcos==0.1.13",
|
||||
"git+https://github.com/mesosphere/dcos-cassandra.git#dcos-cassandra=0.1.0"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"pip": [
|
||||
"dcos<1.0",
|
||||
"git+https://github.com/mesosphere/dcos-helloworld.git#dcos-helloworld=0.1.0"
|
||||
]
|
||||
}
|
||||
@@ -19,8 +19,8 @@
|
||||
"preInstallNotes": "We recommend a minimum of one node with at least 2 CPU's and 1GB of RAM available for the Marathon Service.",
|
||||
"scm": "https://github.com/mesosphere/marathon.git",
|
||||
"tags": [
|
||||
"mesosphere",
|
||||
"framework"
|
||||
"init",
|
||||
"long-running"
|
||||
],
|
||||
"version": "0.9.0"
|
||||
"version": "0.11.1"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"cmd": "LIBPROCESS_PORT=$PORT1 && ./bin/start --master zk://master.mesos:2181/mesos --checkpoint --failover_timeout 604800 --framework_name marathon-user --ha --zk zk://master.mesos:2181/universe/marathon-user --http_port $PORT0 ",
|
||||
"cmd": "LIBPROCESS_PORT=$PORT1 && ./bin/start --master zk://master.mesos:2181/mesos --checkpoint --decline_offer_duration 5000 --http_port $PORT0 --event_stream_max_outstanding_messages 50 --failover_timeout 604800 --framework_name marathon-user --ha --leader_proxy_connection_timeout 5000 --leader_proxy_read_timeout 10000 --local_port_max 20000 --local_port_min 10000 --marathon_store_timeout 2000 --max_tasks_per_offer 1 --max_tasks_per_offer_cycle 1000 --min_revive_offers_interval 5000 --revive_offers_for_new_apps --scale_apps_initial_delay 15000 --scale_apps_interval 300000 --zk_session_timeout 1800000 --zk zk://master.mesos:2181/universe --mesos_leader_ui_url /mesos --zk_compression --zk_compression_threshold 65536 ",
|
||||
"constraints": [
|
||||
[
|
||||
"hostname",
|
||||
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"container": {
|
||||
"docker": {
|
||||
"image": "mesosphere/marathon:v0.9.0",
|
||||
"image": "mesosphere/marathon:v0.11.1",
|
||||
"network": "HOST"
|
||||
},
|
||||
"type": "DOCKER"
|
||||
@@ -17,17 +17,28 @@
|
||||
"env": {
|
||||
"JVM_OPTS": "-Xms256m -Xmx768m"
|
||||
},
|
||||
"healthChecks": [
|
||||
{
|
||||
"gracePeriodSeconds": 120,
|
||||
"intervalSeconds": 10,
|
||||
"maxConsecutiveFailures": 3,
|
||||
"path": "/v2/info",
|
||||
"portIndex": 0,
|
||||
"protocol": "HTTP",
|
||||
"timeoutSeconds": 5
|
||||
}
|
||||
],
|
||||
"id": "marathon-user",
|
||||
"instances": 1,
|
||||
"labels": {
|
||||
"DCOS_PACKAGE_FRAMEWORK_NAME": "marathon-user",
|
||||
"DCOS_PACKAGE_IS_FRAMEWORK": "true",
|
||||
"DCOS_PACKAGE_METADATA": "eyJkZXNjcmlwdGlvbiI6ICJBIGNsdXN0ZXItd2lkZSBpbml0IGFuZCBjb250cm9sIHN5c3RlbSBmb3Igc2VydmljZXMgaW4gY2dyb3VwcyBvciBEb2NrZXIgY29udGFpbmVycy4iLCAiZnJhbWV3b3JrIjogdHJ1ZSwgImltYWdlcyI6IHsiaWNvbi1sYXJnZSI6ICJodHRwczovL2Rvd25sb2Fkcy5tZXNvc3BoZXJlLmlvL21hcmF0aG9uL2Fzc2V0cy9pY29uLXNlcnZpY2UtbWFyYXRob24tbGFyZ2UucG5nIiwgImljb24tbWVkaXVtIjogImh0dHBzOi8vZG93bmxvYWRzLm1lc29zcGhlcmUuaW8vbWFyYXRob24vYXNzZXRzL2ljb24tc2VydmljZS1tYXJhdGhvbi1tZWRpdW0ucG5nIiwgImljb24tc21hbGwiOiAiaHR0cHM6Ly9kb3dubG9hZHMubWVzb3NwaGVyZS5pby9tYXJhdGhvbi9hc3NldHMvaWNvbi1zZXJ2aWNlLW1hcmF0aG9uLXNtYWxsLnBuZyJ9LCAibGljZW5zZXMiOiBbeyJuYW1lIjogIkFwYWNoZSBMaWNlbnNlIFZlcnNpb24gMi4wIiwgInVybCI6ICJodHRwczovL2dpdGh1Yi5jb20vbWVzb3NwaGVyZS9tYXJhdGhvbi9ibG9iL21hc3Rlci9MSUNFTlNFIn1dLCAibWFpbnRhaW5lciI6ICJzdXBwb3J0QG1lc29zcGhlcmUuaW8iLCAibmFtZSI6ICJtYXJhdGhvbiIsICJwb3N0SW5zdGFsbE5vdGVzIjogIk1hcmF0aG9uIERDT1MgU2VydmljZSBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgaW5zdGFsbGVkIVxuXG5cdERvY3VtZW50YXRpb246IGh0dHBzOi8vbWVzb3NwaGVyZS5naXRodWIuaW8vbWFyYXRob25cblx0SXNzdWVzOiBodHRwczovZ2l0aHViLmNvbS9tZXNvc3BoZXJlL21hcmF0aG9uL2lzc3Vlc1xuIiwgInBvc3RVbmluc3RhbGxOb3RlcyI6ICJUaGUgTWFyYXRob24gRENPUyBTZXJ2aWNlIGhhcyBiZWVuIHVuaW5zdGFsbGVkIGFuZCB3aWxsIG5vIGxvbmdlciBydW4uXG5QbGVhc2UgZm9sbG93IHRoZSBpbnN0cnVjdGlvbnMgYXQgaHR0cDovL2RvY3MubWVzb3NwaGVyZS5jb20vc2VydmljZXMvbWFyYXRob24vI3VuaW5zdGFsbCB0byBjbGVhbiB1cCBhbnkgcGVyc2lzdGVkIHN0YXRlIiwgInByZUluc3RhbGxOb3RlcyI6ICJXZSByZWNvbW1lbmQgYSBtaW5pbXVtIG9mIG9uZSBub2RlIHdpdGggYXQgbGVhc3QgMiBDUFUncyBhbmQgMUdCIG9mIFJBTSBhdmFpbGFibGUgZm9yIHRoZSBNYXJhdGhvbiBTZXJ2aWNlLiIsICJzY20iOiAiaHR0cHM6Ly9naXRodWIuY29tL21lc29zcGhlcmUvbWFyYXRob24uZ2l0IiwgInRhZ3MiOiBbIm1lc29zcGhlcmUiLCAiZnJhbWV3b3JrIl0sICJ2ZXJzaW9uIjogIjAuOS4wIn0=",
|
||||
"DCOS_PACKAGE_METADATA": "eyJkZXNjcmlwdGlvbiI6ICJBIGNsdXN0ZXItd2lkZSBpbml0IGFuZCBjb250cm9sIHN5c3RlbSBmb3Igc2VydmljZXMgaW4gY2dyb3VwcyBvciBEb2NrZXIgY29udGFpbmVycy4iLCAiZnJhbWV3b3JrIjogdHJ1ZSwgImltYWdlcyI6IHsiaWNvbi1sYXJnZSI6ICJodHRwczovL2Rvd25sb2Fkcy5tZXNvc3BoZXJlLmlvL21hcmF0aG9uL2Fzc2V0cy9pY29uLXNlcnZpY2UtbWFyYXRob24tbGFyZ2UucG5nIiwgImljb24tbWVkaXVtIjogImh0dHBzOi8vZG93bmxvYWRzLm1lc29zcGhlcmUuaW8vbWFyYXRob24vYXNzZXRzL2ljb24tc2VydmljZS1tYXJhdGhvbi1tZWRpdW0ucG5nIiwgImljb24tc21hbGwiOiAiaHR0cHM6Ly9kb3dubG9hZHMubWVzb3NwaGVyZS5pby9tYXJhdGhvbi9hc3NldHMvaWNvbi1zZXJ2aWNlLW1hcmF0aG9uLXNtYWxsLnBuZyJ9LCAibGljZW5zZXMiOiBbeyJuYW1lIjogIkFwYWNoZSBMaWNlbnNlIFZlcnNpb24gMi4wIiwgInVybCI6ICJodHRwczovL2dpdGh1Yi5jb20vbWVzb3NwaGVyZS9tYXJhdGhvbi9ibG9iL21hc3Rlci9MSUNFTlNFIn1dLCAibWFpbnRhaW5lciI6ICJzdXBwb3J0QG1lc29zcGhlcmUuaW8iLCAibmFtZSI6ICJtYXJhdGhvbiIsICJwb3N0SW5zdGFsbE5vdGVzIjogIk1hcmF0aG9uIERDT1MgU2VydmljZSBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgaW5zdGFsbGVkIVxuXG5cdERvY3VtZW50YXRpb246IGh0dHBzOi8vbWVzb3NwaGVyZS5naXRodWIuaW8vbWFyYXRob25cblx0SXNzdWVzOiBodHRwczovZ2l0aHViLmNvbS9tZXNvc3BoZXJlL21hcmF0aG9uL2lzc3Vlc1xuIiwgInBvc3RVbmluc3RhbGxOb3RlcyI6ICJUaGUgTWFyYXRob24gRENPUyBTZXJ2aWNlIGhhcyBiZWVuIHVuaW5zdGFsbGVkIGFuZCB3aWxsIG5vIGxvbmdlciBydW4uXG5QbGVhc2UgZm9sbG93IHRoZSBpbnN0cnVjdGlvbnMgYXQgaHR0cDovL2RvY3MubWVzb3NwaGVyZS5jb20vc2VydmljZXMvbWFyYXRob24vI3VuaW5zdGFsbCB0byBjbGVhbiB1cCBhbnkgcGVyc2lzdGVkIHN0YXRlIiwgInByZUluc3RhbGxOb3RlcyI6ICJXZSByZWNvbW1lbmQgYSBtaW5pbXVtIG9mIG9uZSBub2RlIHdpdGggYXQgbGVhc3QgMiBDUFUncyBhbmQgMUdCIG9mIFJBTSBhdmFpbGFibGUgZm9yIHRoZSBNYXJhdGhvbiBTZXJ2aWNlLiIsICJzY20iOiAiaHR0cHM6Ly9naXRodWIuY29tL21lc29zcGhlcmUvbWFyYXRob24uZ2l0IiwgInRhZ3MiOiBbImluaXQiLCAibG9uZy1ydW5uaW5nIl0sICJ2ZXJzaW9uIjogIjAuMTEuMSJ9",
|
||||
"DCOS_PACKAGE_NAME": "marathon",
|
||||
"DCOS_PACKAGE_REGISTRY_VERSION": "1.0.0-rc1",
|
||||
"DCOS_PACKAGE_RELEASE": "2",
|
||||
"DCOS_PACKAGE_SOURCE": "https://github.com/mesosphere/universe/archive/cli-tests.zip",
|
||||
"DCOS_PACKAGE_VERSION": "0.9.0"
|
||||
"DCOS_PACKAGE_RELEASE": "6",
|
||||
"DCOS_PACKAGE_SOURCE": "https://github.com/mesosphere/universe/archive/cli-test-2.zip",
|
||||
"DCOS_PACKAGE_VERSION": "0.11.1"
|
||||
},
|
||||
"mem": 1024.0,
|
||||
"ports": [
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
"additionalProperties": false,
|
||||
"description": "Marathon specific configuration properties",
|
||||
"properties": {
|
||||
"access-control-allow-origin": {
|
||||
"description": "The origin(s) to allow in Marathon. Not set by default. Example values are \"'*'\", or \"http://localhost:8888,http://domain.com\"",
|
||||
"type": "string"
|
||||
},
|
||||
"artifact-store": {
|
||||
"description": "URL to the artifact store. Examples: \"hdfs://localhost:54310/path/to/store\", \"file:///var/log/store\". For details, see the artifact store docs: https://mesosphere.github.io/marathon/docs/artifact-store.html.",
|
||||
"type": "string"
|
||||
@@ -19,11 +23,47 @@
|
||||
"minimum": 0.0,
|
||||
"type": "number"
|
||||
},
|
||||
"decline-offer-duration": {
|
||||
"default": 5000,
|
||||
"description": "The duration (milliseconds) for which to decline offers by default",
|
||||
"minimum": 100,
|
||||
"type": "integer"
|
||||
},
|
||||
"default-accepted-resource-roles": {
|
||||
"description": "Default for the defaultAcceptedResourceRoles attribute of all app definitions as a comma-separated list of strings. This defaults to all roles for which this Marathon instance is configured to receive offers.",
|
||||
"type": "string"
|
||||
},
|
||||
"disable-http": {
|
||||
"default": false,
|
||||
"description": "Disable listening for HTTP requests completely. HTTPS is unaffected.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disable_metrics": {
|
||||
"default": false,
|
||||
"description": "Disable metric measurement of service method calls",
|
||||
"type": "boolean"
|
||||
},
|
||||
"enable-https": {
|
||||
"default": false,
|
||||
"description": "Enables the HTTPS protocol. Use in conjunction with ssl-keystore-path and ssl-keystore-password.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"enable-tracing": {
|
||||
"default": false,
|
||||
"description": "Enable trace logging of service method calls",
|
||||
"type": "boolean"
|
||||
},
|
||||
"env-vars-prefix": {
|
||||
"default": "",
|
||||
"description": "Prefix to use for environment variables",
|
||||
"type": "string"
|
||||
},
|
||||
"event-stream-max-outstanding-messages": {
|
||||
"default": 50,
|
||||
"description": "The event stream buffers events, that are not already consumed by clients. This number defines the number of events that get buffered on the server side, before messages are dropped.",
|
||||
"minimum": 10,
|
||||
"type": "integer"
|
||||
},
|
||||
"event-subscriber": {
|
||||
"description": "Event subscriber module to enable. Currently the only valid value is \"http_callback\".",
|
||||
"type": "string"
|
||||
@@ -57,6 +97,11 @@
|
||||
"description": "Pre-configured http callback URLs. Valid only in conjunction with --event_subscriber http_callback. Additional callback URLs may also be set dynamically via the REST API.",
|
||||
"type": "string"
|
||||
},
|
||||
"http-max-concurrent-requests": {
|
||||
"description": "The number of concurrent http requests, that are allowed before rejecting.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"http-port": {
|
||||
"default": 0,
|
||||
"description": "The port on which to listen for HTTP requests.",
|
||||
@@ -87,23 +132,55 @@
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"leader-proxy-connection-timeout": {
|
||||
"default": 5000,
|
||||
"description": "Maximum time, in milliseconds, to wait for connecting to the current Marathon leader from another Marathon instance.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"leader-proxy-read-timeout": {
|
||||
"default": 10000,
|
||||
"description": "Maximum time, in milliseconds, for reading from the current Marathon leader.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"local-port-max": {
|
||||
"default": 20000,
|
||||
"description": "Maximum port number to use when assigning service ports to apps.",
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"local-port-min": {
|
||||
"default": 10000,
|
||||
"description": "Minimum port number to use when assigning service ports to apps.",
|
||||
"maximum": 65535,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"marathon-store-timeout": {
|
||||
"default": 2000,
|
||||
"description": "Maximum time in milliseconds, to wait for persistent storage operations to complete.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"max-apps": {
|
||||
"description": "The maximum number of applications that may be created.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"max-tasks-per-offer": {
|
||||
"default": 1,
|
||||
"description": "Maximally launch this number of tasks per offer.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"max-tasks-per-offer-cycle": {
|
||||
"default": 1000,
|
||||
"description": "Maximally launch this number of tasks per offer cycle.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"mem": {
|
||||
"default": 1024.0,
|
||||
"description": "Memory (MB) to allocate to each Marathon task.",
|
||||
@@ -118,10 +195,21 @@
|
||||
"description": "The path to the Mesos secret file containing the authentication secret.",
|
||||
"type": "string"
|
||||
},
|
||||
"mesos-leader-ui-url": {
|
||||
"default": "/mesos",
|
||||
"description": "The host and port (e.g. http://mesos_host:5050) of the Mesos master.",
|
||||
"type": "string"
|
||||
},
|
||||
"mesos-role": {
|
||||
"description": "Mesos role for this framework.",
|
||||
"type": "string"
|
||||
},
|
||||
"min-revive-offers-interval": {
|
||||
"default": 5000,
|
||||
"description": "Do not ask for all offers (also already seen ones) more often than this interval (ms).",
|
||||
"minimum": 200,
|
||||
"type": "integer"
|
||||
},
|
||||
"reconciliation-initial-delay": {
|
||||
"description": "The delay, in milliseconds, before Marathon begins to periodically perform task reconciliation operations.",
|
||||
"minimum": 0,
|
||||
@@ -132,6 +220,23 @@
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"revive-offers-for-new-apps": {
|
||||
"default": true,
|
||||
"description": "Whether to call reviveOffers for new or changed apps.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"scale-apps-initial-delay": {
|
||||
"default": 15000,
|
||||
"description": "This is the length of time, in milliseconds, before Marathon begins to periodically attempt to scale apps",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"scale-apps-interval": {
|
||||
"default": 300000,
|
||||
"description": "This is the length of time, in milliseconds, between task scale apps.",
|
||||
"minimum": 1000,
|
||||
"type": "integer"
|
||||
},
|
||||
"ssl-keystore-password": {
|
||||
"description": "Password for the keystore supplied with the marathon/ssl-keystore-path option.",
|
||||
"type": "string"
|
||||
@@ -154,11 +259,28 @@
|
||||
"description": "Parent ZooKeeper URL for storing state. The framework name is joined to the path of this value. Format: zk://host1:port1,host2:port2,.../path",
|
||||
"type": "string"
|
||||
},
|
||||
"zk-compression": {
|
||||
"default": true,
|
||||
"description": "Enable compression of zk nodes, if the size of the node is bigger than the configured threshold.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"zk-compression-threshold": {
|
||||
"default": 65536,
|
||||
"description": "Threshold in bytes, when compression is applied to the zk node (Default: 64 KB).",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"zk-max-versions": {
|
||||
"description": "Limit the number of versions stored for one entity.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"zk-session-timeout": {
|
||||
"default": 1800000,
|
||||
"description": "The timeout for zookeeper sessions in milliseconds.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"zk-timeout": {
|
||||
"description": "Timeout for ZooKeeper in milliseconds.",
|
||||
"minimum": 0,
|
||||
@@ -177,7 +299,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"mesos": {
|
||||
"depscription": "Mesos specific configuration properties",
|
||||
"description": "Mesos specific configuration properties",
|
||||
"properties": {
|
||||
"master": {
|
||||
"default": "zk://master.mesos:2181/mesos",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
0.11.1
|
||||
0.11.0
|
||||
0.10.1
|
||||
0.9.2
|
||||
0.9.0
|
||||
0.9.0-RC3
|
||||
0.8.1
|
||||
|
||||
8
cli/tests/data/service/marathon-user.json
Normal file
8
cli/tests/data/service/marathon-user.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"marathon": {
|
||||
"zk": "zk://master.mesos:2181/universe/marathon-user",
|
||||
"framework-name": "marathon-user",
|
||||
"mem": 850,
|
||||
"cpus": 1
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"marathon": {
|
||||
"zk": "zk://master.mesos:2181/universe2",
|
||||
"mem": 512,
|
||||
"zk": "zk://master.mesos:2181/universe/marathon-user2",
|
||||
"framework-name": "marathon-user",
|
||||
"mem": 850,
|
||||
"cpus": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
cache = "tmp/cache"
|
||||
sources = [ "https://github.com/mesosphere/universe/archive/cli-tests.zip",]
|
||||
sources = [ "https://github.com/mesosphere/universe/archive/cli-test-2.zip",]
|
||||
[core]
|
||||
timeout = 5
|
||||
dcos_url = "https://dcos.snakeoil.mesosphere.com"
|
||||
|
||||
7
cli/tests/fixtures/node.py
vendored
7
cli/tests/fixtures/node.py
vendored
@@ -28,6 +28,7 @@ def slave_fixture():
|
||||
"pid": "slave(1)@172.17.8.101:5051",
|
||||
"registered_time": 1435625024.42234,
|
||||
"reregistered_time": 1435625024.42234,
|
||||
"reserved_resources": {},
|
||||
"resources": {
|
||||
"cpus": 4.0,
|
||||
"disk": 10823,
|
||||
@@ -35,6 +36,12 @@ def slave_fixture():
|
||||
"ports": ("[1025-2180, 2182-3887, 3889-5049, 5052-8079, " +
|
||||
"8082-8180, 8182-65535]")
|
||||
},
|
||||
"unreserved_resources": {
|
||||
"cpus": 4,
|
||||
"disk": 10823,
|
||||
"mem": 2933,
|
||||
"ports": "[1025-2180, 2182-3887, 3889-5049, 5052-32000]"
|
||||
},
|
||||
"used_resources": {
|
||||
"cpus": 0.0,
|
||||
"disk": 0,
|
||||
|
||||
1
cli/tests/fixtures/service.py
vendored
1
cli/tests/fixtures/service.py
vendored
@@ -9,6 +9,7 @@ def framework_fixture():
|
||||
|
||||
return Framework({
|
||||
"active": True,
|
||||
"capabilities": [],
|
||||
"checkpoint": True,
|
||||
"completed_tasks": [],
|
||||
"executors": [],
|
||||
|
||||
@@ -196,11 +196,13 @@ def watch_all_deployments(count=300):
|
||||
watch_deployment(dep['id'], count)
|
||||
|
||||
|
||||
def wait_for_service(service_name, max_count=300):
|
||||
def wait_for_service(service_name, number_of_services=1, max_count=300):
|
||||
"""Wait for service to register with Mesos
|
||||
|
||||
:param service_name: name of service
|
||||
:type service_name: str
|
||||
:param number_of_services: number of services with that name
|
||||
:type number_of_services: int
|
||||
:param max_count: max number of seconds to wait
|
||||
:type max_count: int
|
||||
:rtype: None
|
||||
@@ -210,24 +212,25 @@ def wait_for_service(service_name, max_count=300):
|
||||
while count < max_count:
|
||||
services = get_services()
|
||||
|
||||
for service in services:
|
||||
if service['name'] == service_name:
|
||||
return
|
||||
if (len([service for service in services
|
||||
if service['name'] == service_name]) >= number_of_services):
|
||||
return
|
||||
|
||||
count += 1
|
||||
|
||||
|
||||
def add_app(app_path, deploy=False):
|
||||
def add_app(app_path, wait=True):
|
||||
""" Add an app, and wait for it to deploy
|
||||
|
||||
:param app_path: path to app's json definition
|
||||
:type app_path: str
|
||||
:param wait: whether to wait for the deploy
|
||||
:type wait: bool
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
assert_command(['dcos', 'marathon', 'app', 'add', app_path])
|
||||
|
||||
if deploy:
|
||||
if wait:
|
||||
watch_all_deployments()
|
||||
|
||||
|
||||
@@ -447,7 +450,7 @@ def file_json(path):
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def app(path, app_id, deploy=False):
|
||||
def app(path, app_id, wait=True):
|
||||
"""Context manager that deploys an app on entrance, and removes it on
|
||||
exit.
|
||||
|
||||
@@ -455,14 +458,17 @@ def app(path, app_id, deploy=False):
|
||||
:type path: str
|
||||
:param app_id: app id
|
||||
:type app_id: str
|
||||
:param wait: whether to wait for the deploy
|
||||
:type wait: bool
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
add_app(path, deploy)
|
||||
add_app(path, wait)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
remove_app(app_id)
|
||||
watch_all_deployments()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
||||
@@ -80,7 +80,7 @@ core.ssl_verify=false
|
||||
core.timeout=5
|
||||
package.cache=tmp/cache
|
||||
package.sources=['https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip']
|
||||
cli-test-2.zip']
|
||||
"""
|
||||
assert_command(['dcos', 'config', 'show'],
|
||||
stdout=stdout,
|
||||
@@ -178,11 +178,11 @@ def test_append_empty_list(env):
|
||||
config_set('package.sources', '[]', env)
|
||||
_append_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
_get_value(
|
||||
'package.sources',
|
||||
['https://github.com/mesosphere/universe/archive/cli-tests.zip'],
|
||||
['https://github.com/mesosphere/universe/archive/cli-test-2.zip'],
|
||||
env)
|
||||
|
||||
|
||||
@@ -190,11 +190,11 @@ def test_prepend_empty_list(env):
|
||||
config_set('package.sources', '[]', env)
|
||||
_prepend_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
_get_value(
|
||||
'package.sources',
|
||||
['https://github.com/mesosphere/universe/archive/cli-tests.zip'],
|
||||
['https://github.com/mesosphere/universe/archive/cli-test-2.zip'],
|
||||
env)
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ def test_append_list(env):
|
||||
env)
|
||||
_get_value(
|
||||
'package.sources',
|
||||
['https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
['https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
'https://github.com/mesosphere/universe/archive/version-2.x.zip'],
|
||||
env)
|
||||
config_unset('package.sources', '1', env)
|
||||
@@ -219,7 +219,7 @@ def test_prepend_list(env):
|
||||
_get_value(
|
||||
'package.sources',
|
||||
['https://github.com/mesosphere/universe/archive/version-2.x.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip'],
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip'],
|
||||
env)
|
||||
config_unset('package.sources', '0', env)
|
||||
|
||||
@@ -270,7 +270,7 @@ def test_unset_output(env):
|
||||
def test_unset_index_output(env):
|
||||
stdout = (
|
||||
b"[package.sources]: removed element "
|
||||
b"'https://github.com/mesosphere/universe/archive/cli-tests.zip' "
|
||||
b"'https://github.com/mesosphere/universe/archive/cli-test-2.zip' "
|
||||
b"at index '0'\n"
|
||||
)
|
||||
|
||||
@@ -280,14 +280,14 @@ def test_unset_index_output(env):
|
||||
|
||||
_prepend_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
|
||||
|
||||
def test_set_whole_list(env):
|
||||
config_set(
|
||||
'package.sources',
|
||||
'["https://github.com/mesosphere/universe/archive/cli-tests.zip"]',
|
||||
'["https://github.com/mesosphere/universe/archive/cli-test-2.zip"]',
|
||||
env)
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ def test_unset_list_index(env):
|
||||
env)
|
||||
_prepend_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ def test_validate(env):
|
||||
|
||||
|
||||
def test_validation_error(env):
|
||||
source = ["https://github.com/mesosphere/universe/archive/cli-tests.zip"]
|
||||
source = ["https://github.com/mesosphere/universe/archive/cli-test-2.zip"]
|
||||
config_unset('package.sources', None, env)
|
||||
|
||||
stdout = b"Error: missing required property 'sources'.\n"
|
||||
@@ -422,12 +422,12 @@ def test_url_validation(env):
|
||||
|
||||
def test_append_url_validation(env):
|
||||
default_value = ('["https://github.com/mesosphere/universe/archive/'
|
||||
'cli-tests.zip"]')
|
||||
'cli-test-2.zip"]')
|
||||
|
||||
config_set('package.sources', '[]', env)
|
||||
_append_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
_append_value(
|
||||
'package.sources',
|
||||
@@ -450,12 +450,12 @@ def test_append_url_validation(env):
|
||||
|
||||
def test_prepend_url_validation(env):
|
||||
default_value = ('["https://github.com/mesosphere/universe/archive/'
|
||||
'cli-tests.zip"]')
|
||||
'cli-test-2.zip"]')
|
||||
|
||||
config_set('package.sources', '[]', env)
|
||||
_prepend_value(
|
||||
'package.sources',
|
||||
'https://github.com/mesosphere/universe/archive/cli-tests.zip',
|
||||
'https://github.com/mesosphere/universe/archive/cli-test-2.zip',
|
||||
env)
|
||||
_prepend_value(
|
||||
'package.sources',
|
||||
|
||||
@@ -13,6 +13,8 @@ from .common import (app, assert_command, assert_lines, config_set,
|
||||
config_unset, exec_command, list_deployments, popen_tty,
|
||||
show_app, watch_all_deployments, watch_deployment)
|
||||
|
||||
_ZERO_INSTANCE_APP_INSTANCES = 100
|
||||
|
||||
|
||||
def test_help():
|
||||
stdout = b"""Deploy and manage applications on the DCOS
|
||||
@@ -329,8 +331,7 @@ def test_stop_missing_app():
|
||||
def test_stop_app():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
watch_all_deployments()
|
||||
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'app', 'stop', 'zero-instance-app'])
|
||||
@@ -356,29 +357,26 @@ def test_update_missing_app():
|
||||
returncode=1)
|
||||
|
||||
|
||||
def test_update_missing_field():
|
||||
with _zero_instance_app():
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'app', 'update',
|
||||
'zero-instance-app', 'missing="a string"'])
|
||||
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
assert stderr.decode('utf-8').startswith(
|
||||
"Error: 'missing' is not a valid property. "
|
||||
"Possible properties are: ")
|
||||
|
||||
|
||||
def test_update_bad_type():
|
||||
with _zero_instance_app():
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'app', 'update',
|
||||
'zero-instance-app', 'cpus="a string"'])
|
||||
|
||||
stderr_end = b"""{
|
||||
"details": [
|
||||
{
|
||||
"errors": [
|
||||
"error.expected.jsnumber"
|
||||
],
|
||||
"path": "/cpus"
|
||||
}
|
||||
],
|
||||
"message": "Invalid JSON"
|
||||
}
|
||||
"""
|
||||
assert returncode == 1
|
||||
assert stderr.decode('utf-8').startswith(
|
||||
"Unable to parse 'a string' as a float: could not convert string "
|
||||
"to float: ")
|
||||
assert stderr_end in stderr
|
||||
assert stdout == b''
|
||||
|
||||
|
||||
@@ -388,6 +386,8 @@ def test_update_invalid_request():
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
stderr = stderr.decode()
|
||||
# TODO (tamar): this becomes 'Error: App '/{' does not exist\n"'
|
||||
# in Marathon 0.11.0
|
||||
assert stderr.startswith('Error on request')
|
||||
assert stderr.endswith('HTTP 400: Bad Request\n')
|
||||
|
||||
@@ -456,9 +456,7 @@ def test_restarting_missing_app():
|
||||
def test_restarting_app():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
|
||||
watch_all_deployments()
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'app', 'restart', 'zero-instance-app'])
|
||||
|
||||
@@ -508,7 +506,7 @@ def test_list_empty_deployment():
|
||||
|
||||
def test_list_deployment():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', _ZERO_INSTANCE_APP_INSTANCES)
|
||||
list_deployments(1)
|
||||
|
||||
|
||||
@@ -519,7 +517,7 @@ def test_list_deployment_table():
|
||||
"""
|
||||
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', _ZERO_INSTANCE_APP_INSTANCES)
|
||||
assert_lines(['dcos', 'marathon', 'deployment', 'list'], 2)
|
||||
|
||||
|
||||
@@ -531,7 +529,7 @@ def test_list_deployment_missing_app():
|
||||
|
||||
def test_list_deployment_app():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', _ZERO_INSTANCE_APP_INSTANCES)
|
||||
list_deployments(1, 'zero-instance-app')
|
||||
|
||||
|
||||
@@ -544,7 +542,7 @@ def test_rollback_missing_deployment():
|
||||
|
||||
def test_rollback_deployment():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', _ZERO_INSTANCE_APP_INSTANCES)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
|
||||
returncode, stdout, stderr = exec_command(
|
||||
@@ -557,12 +555,13 @@ def test_rollback_deployment():
|
||||
assert 'version' in result
|
||||
assert stderr == b''
|
||||
|
||||
watch_all_deployments()
|
||||
list_deployments(0)
|
||||
|
||||
|
||||
def test_stop_deployment():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', _ZERO_INSTANCE_APP_INSTANCES)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
|
||||
assert_command(
|
||||
@@ -577,7 +576,7 @@ def test_watching_missing_deployment():
|
||||
|
||||
def test_watching_deployment():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
_start_app('zero-instance-app', 10)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
list_deployments(0, 'zero-instance-app')
|
||||
@@ -595,8 +594,7 @@ def test_list_empty_task_not_running_app():
|
||||
def test_list_tasks():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
watch_all_deployments()
|
||||
_list_tasks(3)
|
||||
|
||||
|
||||
@@ -610,16 +608,14 @@ def test_list_tasks_table():
|
||||
def test_list_app_tasks():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
watch_all_deployments()
|
||||
_list_tasks(3, 'zero-instance-app')
|
||||
|
||||
|
||||
def test_list_missing_app_tasks():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
watch_all_deployments()
|
||||
_list_tasks(0, 'missing-id')
|
||||
|
||||
|
||||
@@ -638,8 +634,7 @@ def test_show_missing_task():
|
||||
def test_show_task():
|
||||
with _zero_instance_app():
|
||||
_start_app('zero-instance-app', 3)
|
||||
result = list_deployments(1, 'zero-instance-app')
|
||||
watch_deployment(result[0]['id'], 60)
|
||||
watch_all_deployments()
|
||||
result = _list_tasks(3, 'zero-instance-app')
|
||||
|
||||
returncode, stdout, stderr = exec_command(
|
||||
@@ -667,10 +662,11 @@ def test_bad_configuration():
|
||||
|
||||
|
||||
def test_app_locked_error():
|
||||
with app('tests/data/marathon/apps/sleep_two_instances.json',
|
||||
'/sleep-two-instances'):
|
||||
with app('tests/data/marathon/apps/sleep_many_instances.json',
|
||||
'/sleep-many-instances',
|
||||
wait=False):
|
||||
assert_command(
|
||||
['dcos', 'marathon', 'app', 'stop', 'sleep-two-instances'],
|
||||
['dcos', 'marathon', 'app', 'stop', 'sleep-many-instances'],
|
||||
returncode=1,
|
||||
stderr=(b'App or group is locked by one or more deployments. '
|
||||
b'Override with --force.\n'))
|
||||
|
||||
@@ -42,42 +42,27 @@ def test_show_group():
|
||||
_show_group('test-group')
|
||||
|
||||
|
||||
def test_add_bad_app():
|
||||
with open('tests/data/marathon/groups/bad_app.json') as fd:
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'group', 'add'],
|
||||
stdin=fd)
|
||||
|
||||
expected = "Error: Additional properties are not allowed" + \
|
||||
" ('badtype' was unexpected)"
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
assert stderr.decode('utf-8').startswith(expected)
|
||||
|
||||
|
||||
def test_add_bad_group():
|
||||
with open('tests/data/marathon/groups/bad_group.json') as fd:
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'group', 'add'],
|
||||
stdin=fd)
|
||||
|
||||
expected = "Error: Additional properties are not allowed" + \
|
||||
" ('fakeapp' was unexpected)"
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
assert stderr.decode('utf-8').startswith(expected)
|
||||
|
||||
|
||||
def test_add_bad_complicated_group():
|
||||
with open('tests/data/marathon/groups/complicated_bad.json') as fd:
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'group', 'add'],
|
||||
stdin=fd)
|
||||
|
||||
err = "Error: missing required property 'id'"
|
||||
err = b"""{
|
||||
"details": [
|
||||
{
|
||||
"errors": [
|
||||
"error.path.missing"
|
||||
],
|
||||
"path": "/groups(0)/apps(0)/id"
|
||||
}
|
||||
],
|
||||
"message": "Invalid JSON"
|
||||
}
|
||||
"""
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
assert err in stderr.decode('utf-8')
|
||||
assert err in stderr
|
||||
|
||||
|
||||
def test_update_group():
|
||||
@@ -110,19 +95,6 @@ def test_update_missing_group():
|
||||
returncode=1)
|
||||
|
||||
|
||||
def test_update_missing_field():
|
||||
with _group(GOOD_GROUP, 'test-group'):
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'marathon', 'group', 'update',
|
||||
'test-group/sleep', 'missing="a string"'])
|
||||
|
||||
assert returncode == 1
|
||||
assert stdout == b''
|
||||
assert stderr.decode('utf-8').startswith(
|
||||
"Error: 'missing' is not a valid property. "
|
||||
"Possible properties are: ")
|
||||
|
||||
|
||||
def test_scale_group():
|
||||
_deploy_group('tests/data/marathon/groups/scale.json')
|
||||
returncode, stdout, stderr = exec_command(['dcos', 'marathon', 'group',
|
||||
|
||||
@@ -51,7 +51,7 @@ def _chronos_description(app_ids):
|
||||
"maintainer": "support@mesosphere.io",
|
||||
"name": "chronos",
|
||||
"packageSource": "https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip",
|
||||
cli-test-2.zip",
|
||||
"postInstallNotes": "Chronos DCOS Service has been successfully "
|
||||
"installed!\n\n\tDocumentation: http://mesos."
|
||||
"github.io/chronos\n\tIssues: https://github.com/"
|
||||
@@ -64,13 +64,14 @@ cli-tests.zip",
|
||||
"preInstallNotes": "We recommend a minimum of one node with at least "
|
||||
"1 CPU and 2GB of RAM available for the Chronos "
|
||||
"Service.",
|
||||
"releaseVersion": "0",
|
||||
"releaseVersion": "1",
|
||||
"scm": "https://github.com/mesos/chronos.git",
|
||||
"tags": [
|
||||
"mesosphere",
|
||||
"framework"
|
||||
"cron",
|
||||
"analytics",
|
||||
"batch"
|
||||
],
|
||||
"version": "2.3.4"
|
||||
"version": "2.4.0"
|
||||
}]
|
||||
|
||||
return (json.dumps(result, sort_keys=True, indent=2).replace(' \n', '\n') +
|
||||
@@ -96,8 +97,8 @@ def test_version():
|
||||
|
||||
|
||||
def test_sources_list():
|
||||
stdout = b"7b77ff84c23ffc575870c1eade68a28767ce0291 " + \
|
||||
b"https://github.com/mesosphere/universe/archive/cli-tests.zip\n"
|
||||
stdout = b"1a9bef0c579dd0692af9c6ba22c3ec910fb03efc " + \
|
||||
b"https://github.com/mesosphere/universe/archive/cli-test-2.zip\n"
|
||||
assert_command(['dcos', 'package', 'sources'],
|
||||
stdout=stdout)
|
||||
|
||||
@@ -146,8 +147,8 @@ def test_describe():
|
||||
|
||||
def test_describe_cli():
|
||||
stdout = file_json(
|
||||
'tests/data/package/json/test_describe_cli_helloworld.json')
|
||||
assert_command(['dcos', 'package', 'describe', 'helloworld', '--cli'],
|
||||
'tests/data/package/json/test_describe_cli_cassandra.json')
|
||||
assert_command(['dcos', 'package', 'describe', 'cassandra', '--cli'],
|
||||
stdout=stdout)
|
||||
|
||||
|
||||
@@ -219,7 +220,7 @@ def test_describe_app_cli():
|
||||
stdout = file_bytes(
|
||||
'tests/data/package/json/test_describe_app_cli.json')
|
||||
assert_command(
|
||||
['dcos', 'package', 'describe', 'helloworld', '--app', '--cli'],
|
||||
['dcos', 'package', 'describe', 'cassandra', '--app', '--cli'],
|
||||
stdout=stdout)
|
||||
|
||||
|
||||
@@ -298,9 +299,9 @@ def test_install_specific_version():
|
||||
|
||||
|
||||
def test_install_bad_package_version():
|
||||
stderr = b'Version a.b.c of package [helloworld] is not available\n'
|
||||
stderr = b'Version a.b.c of package [cassandra] is not available\n'
|
||||
assert_command(
|
||||
['dcos', 'package', 'install', 'helloworld',
|
||||
['dcos', 'package', 'install', 'cassandra',
|
||||
'--package-version=a.b.c'],
|
||||
returncode=1,
|
||||
stderr=stderr)
|
||||
@@ -323,7 +324,7 @@ b3NwaGVyZS9kY29zLWhlbGxvd29ybGQifQ=="""
|
||||
CJdfQ=="""
|
||||
|
||||
expected_source = b"""https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip"""
|
||||
cli-test-2.zip"""
|
||||
|
||||
expected_labels = {
|
||||
'DCOS_PACKAGE_METADATA': expected_metadata,
|
||||
@@ -375,12 +376,12 @@ cli-tests.zip"""
|
||||
|
||||
def test_install_with_id(zk_znode):
|
||||
args = ['--app-id=chronos-1', '--yes']
|
||||
stdout = (b'Installing Marathon app for package [chronos] version [2.3.4] '
|
||||
stdout = (b'Installing Marathon app for package [chronos] version [2.4.0] '
|
||||
b'with app id [chronos-1]\n')
|
||||
_install_chronos(args=args, stdout=stdout)
|
||||
|
||||
args = ['--app-id=chronos-2', '--yes']
|
||||
stdout = (b'Installing Marathon app for package [chronos] version [2.3.4] '
|
||||
stdout = (b'Installing Marathon app for package [chronos] version [2.4.0] '
|
||||
b'with app id [chronos-2]\n')
|
||||
_install_chronos(args=args, stdout=stdout)
|
||||
|
||||
@@ -433,7 +434,7 @@ def test_uninstall_cli():
|
||||
"maintainer": "support@mesosphere.io",
|
||||
"name": "helloworld",
|
||||
"packageSource": "https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip",
|
||||
cli-test-2.zip",
|
||||
"postInstallNotes": "A sample post-installation message",
|
||||
"preInstallNotes": "A sample pre-installation message",
|
||||
"releaseVersion": "0",
|
||||
@@ -551,7 +552,7 @@ def test_list_cli():
|
||||
"maintainer": "support@mesosphere.io",
|
||||
"name": "helloworld",
|
||||
"packageSource": "https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip",
|
||||
cli-test-2.zip",
|
||||
"postInstallNotes": "A sample post-installation message",
|
||||
"preInstallNotes": "A sample pre-installation message",
|
||||
"releaseVersion": "0",
|
||||
@@ -585,7 +586,7 @@ cli-tests.zip",
|
||||
"maintainer": "support@mesosphere.io",
|
||||
"name": "helloworld",
|
||||
"packageSource": "https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip",
|
||||
cli-test-2.zip",
|
||||
"postInstallNotes": "A sample post-installation message",
|
||||
"preInstallNotes": "A sample pre-installation message",
|
||||
"releaseVersion": "0",
|
||||
@@ -623,7 +624,7 @@ def test_uninstall_multiple_frameworknames(zk_znode):
|
||||
_uninstall_chronos(
|
||||
args=['--app-id=chronos-user-1'],
|
||||
returncode=1,
|
||||
stderr='Uninstalled package [chronos] version [2.3.4]\n'
|
||||
stderr='Uninstalled package [chronos] version [2.4.0]\n'
|
||||
'The Chronos DCOS Service has been uninstalled and will no '
|
||||
'longer run.\nPlease follow the instructions at http://docs.'
|
||||
'mesosphere.com/services/chronos/#uninstall to clean up any '
|
||||
@@ -633,7 +634,7 @@ def test_uninstall_multiple_frameworknames(zk_znode):
|
||||
_uninstall_chronos(
|
||||
args=['--app-id=chronos-user-2'],
|
||||
returncode=1,
|
||||
stderr='Uninstalled package [chronos] version [2.3.4]\n'
|
||||
stderr='Uninstalled package [chronos] version [2.4.0]\n'
|
||||
'The Chronos DCOS Service has been uninstalled and will no '
|
||||
'longer run.\nPlease follow the instructions at http://docs.'
|
||||
'mesosphere.com/services/chronos/#uninstall to clean up any '
|
||||
@@ -648,7 +649,7 @@ def test_uninstall_multiple_frameworknames(zk_znode):
|
||||
|
||||
def test_search():
|
||||
returncode, stdout, stderr = exec_command(
|
||||
['dcos', 'package', 'search', 'framework', '--json'])
|
||||
['dcos', 'package', 'search', 'cron', '--json'])
|
||||
|
||||
assert returncode == 0
|
||||
assert b'chronos' in stdout
|
||||
@@ -660,7 +661,7 @@ def test_search():
|
||||
assert returncode == 0
|
||||
assert b'"packages": []' in stdout
|
||||
assert b'"source": "https://github.com/mesosphere/universe/archive/\
|
||||
cli-tests.zip"' in stdout
|
||||
cli-test-2.zip"' in stdout
|
||||
assert stderr == b''
|
||||
|
||||
returncode, stdout, stderr = exec_command(
|
||||
@@ -704,7 +705,7 @@ def test_search_ends_with_wildcard():
|
||||
|
||||
registries = json.loads(stdout.decode('utf-8'))
|
||||
for registry in registries:
|
||||
assert len(registry['packages']) == 3
|
||||
assert len(registry['packages']) == 2
|
||||
|
||||
|
||||
def test_search_start_with_wildcard():
|
||||
@@ -802,7 +803,7 @@ def _install_chronos(
|
||||
args=['--yes'],
|
||||
returncode=0,
|
||||
stdout=b'Installing Marathon app for package [chronos] '
|
||||
b'version [2.3.4]\n',
|
||||
b'version [2.4.0]\n',
|
||||
stderr=b'',
|
||||
preInstallNotes=b'We recommend a minimum of one node with at least 1 '
|
||||
b'CPU and 2GB of RAM available for the Chronos '
|
||||
|
||||
@@ -5,11 +5,14 @@ import time
|
||||
import dcos.util as util
|
||||
from dcos.util import create_schema
|
||||
|
||||
import pytest
|
||||
|
||||
from ..fixtures.service import framework_fixture
|
||||
from .common import (assert_command, assert_lines, delete_zk_node,
|
||||
delete_zk_nodes, exec_command, get_services,
|
||||
package_install, package_uninstall, service_shutdown,
|
||||
ssh_output, watch_all_deployments)
|
||||
package_install, package_uninstall, remove_app,
|
||||
service_shutdown, ssh_output, wait_for_service,
|
||||
watch_all_deployments)
|
||||
|
||||
|
||||
def setup_module(module):
|
||||
@@ -19,7 +22,7 @@ def setup_module(module):
|
||||
def teardown_module(module):
|
||||
package_uninstall(
|
||||
'chronos',
|
||||
stderr=b'Uninstalled package [chronos] version [2.3.4]\n'
|
||||
stderr=b'Uninstalled package [chronos] version [2.4.0]\n'
|
||||
b'The Chronos DCOS Service has been uninstalled and will no '
|
||||
b'longer run.\nPlease follow the instructions at http://docs.'
|
||||
b'mesosphere.com/services/chronos/#uninstall to clean up any '
|
||||
@@ -86,6 +89,8 @@ def test_service_inactive():
|
||||
|
||||
delete_zk_node('cassandra-mesos')
|
||||
|
||||
package_uninstall('cassandra')
|
||||
|
||||
|
||||
def test_service_completed():
|
||||
package_install('cassandra', True)
|
||||
@@ -116,6 +121,8 @@ def test_service_completed():
|
||||
assert len(services) >= 3
|
||||
assert any(service['id'] == cassandra_id for service in services)
|
||||
|
||||
package_uninstall('cassandra')
|
||||
|
||||
|
||||
def test_log():
|
||||
returncode, stdout, stderr = exec_command(
|
||||
@@ -174,10 +181,12 @@ def test_log_config():
|
||||
|
||||
|
||||
def test_log_follow():
|
||||
wait_for_service('chronos')
|
||||
proc = subprocess.Popen(['dcos', 'service', 'log', 'chronos', '--follow'],
|
||||
preexec_fn=os.setsid,
|
||||
stdout=subprocess.PIPE)
|
||||
time.sleep(3)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
proc.poll()
|
||||
assert proc.returncode is None
|
||||
@@ -190,11 +199,17 @@ def test_log_lines():
|
||||
assert_lines(['dcos', 'service', 'log', 'chronos', '--lines=4'], 4)
|
||||
|
||||
|
||||
@pytest.mark.skipif(True, reason='Broken Marathon but we need to release')
|
||||
def test_log_multiple_apps():
|
||||
package_install('marathon', True)
|
||||
package_install('marathon', True,
|
||||
package_install('marathon',
|
||||
True,
|
||||
['--options=tests/data/service/marathon-user.json'])
|
||||
package_install('marathon',
|
||||
True,
|
||||
['--options=tests/data/service/marathon-user2.json',
|
||||
'--app-id=marathon-user2'])
|
||||
wait_for_service('marathon-user', number_of_services=2)
|
||||
|
||||
try:
|
||||
stderr = (b'Multiple marathon apps found for service name ' +
|
||||
b'[marathon-user]: [/marathon-user], [/marathon-user2]\n')
|
||||
@@ -202,20 +217,15 @@ def test_log_multiple_apps():
|
||||
returncode=1,
|
||||
stderr=stderr)
|
||||
finally:
|
||||
# Uninstall notes and message are printed twice because --all will
|
||||
# uninstall two packages
|
||||
package_uninstall(
|
||||
'marathon', ['--all'],
|
||||
stderr=b'Uninstalled package [marathon] version [0.9.0]\n'
|
||||
b'The Marathon DCOS Service has been uninstalled and will '
|
||||
b'no longer run.\nPlease follow the instructions at http://'
|
||||
b'docs.mesosphere.com/services/marathon/#uninstall to '
|
||||
b'clean up any persisted state\n'
|
||||
b'Uninstalled package [marathon] version [0.9.0]\n'
|
||||
b'The Marathon DCOS Service has been uninstalled and will '
|
||||
b'no longer run.\nPlease follow the instructions at http://'
|
||||
b'docs.mesosphere.com/services/marathon/#uninstall to '
|
||||
b'clean up any persisted state\n')
|
||||
# We can't use `dcos package uninstall`. The services have the same
|
||||
# name. Manually remove the dcos services.
|
||||
remove_app('marathon-user')
|
||||
remove_app('marathon-user2')
|
||||
for service in get_services():
|
||||
if service['name'] == 'marathon-user':
|
||||
service_shutdown(service['id'])
|
||||
|
||||
delete_zk_node('universe')
|
||||
|
||||
|
||||
def test_log_no_apps():
|
||||
|
||||
@@ -34,11 +34,11 @@ NUM_TASKS = len(INIT_APPS)
|
||||
|
||||
def setup_module():
|
||||
# create a completed task
|
||||
with app(SLEEP_COMPLETED, 'test-app-completed', True):
|
||||
with app(SLEEP_COMPLETED, 'test-app-completed'):
|
||||
pass
|
||||
|
||||
for app_ in INIT_APPS:
|
||||
add_app(app_[0], True)
|
||||
add_app(app_[0])
|
||||
|
||||
|
||||
def teardown_module():
|
||||
@@ -170,7 +170,7 @@ def test_log_lines_invalid():
|
||||
def test_log_follow():
|
||||
""" Test --follow """
|
||||
# verify output
|
||||
with app(FOLLOW, 'follow', True):
|
||||
with app(FOLLOW, 'follow'):
|
||||
proc = subprocess.Popen(['dcos', 'task', 'log', 'follow', '--follow'],
|
||||
stdout=subprocess.PIPE)
|
||||
|
||||
@@ -205,7 +205,7 @@ def test_log_two_tasks():
|
||||
|
||||
def test_log_two_tasks_follow():
|
||||
""" Test tailing a single file on two separate tasks with --follow """
|
||||
with app(TWO_TASKS_FOLLOW, 'two-tasks-follow', True):
|
||||
with app(TWO_TASKS_FOLLOW, 'two-tasks-follow'):
|
||||
proc = subprocess.Popen(
|
||||
['dcos', 'task', 'log', 'two-tasks-follow', '--follow'],
|
||||
stdout=subprocess.PIPE)
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import collections
|
||||
import json
|
||||
|
||||
import pkg_resources
|
||||
from dcos import util
|
||||
from dcoscli.marathon import main
|
||||
|
||||
import pytest
|
||||
|
||||
ResourceData = collections.namedtuple(
|
||||
'ResourceData',
|
||||
['properties', 'expected'])
|
||||
|
||||
|
||||
def get_clean_app_response():
|
||||
return json.loads(
|
||||
pkg_resources.resource_string(
|
||||
'tests',
|
||||
'data/marathon/apps/cleaned_response.json').decode('utf-8'))
|
||||
|
||||
|
||||
@pytest.fixture(params=[
|
||||
ResourceData(
|
||||
properties=json.loads(
|
||||
pkg_resources.resource_string(
|
||||
'tests',
|
||||
'data/marathon/apps/response.json').decode('utf-8')),
|
||||
expected=get_clean_app_response()
|
||||
)])
|
||||
def resource_data(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_clean_up_resource_definition(resource_data):
|
||||
result = main._clean_up_resource_definition(resource_data.properties)
|
||||
assert result == resource_data.expected
|
||||
|
||||
|
||||
schema = main._data_schema()
|
||||
|
||||
|
||||
ValidationCheck = collections.namedtuple(
|
||||
'ValidationCheck',
|
||||
['properties', 'expected'])
|
||||
|
||||
|
||||
@pytest.fixture(params=[
|
||||
ValidationCheck(
|
||||
properties=get_clean_app_response(),
|
||||
expected=[]),
|
||||
ValidationCheck(
|
||||
properties=json.loads(
|
||||
pkg_resources.resource_string(
|
||||
'tests',
|
||||
'data/marathon/groups/complicated.json').decode('utf-8')),
|
||||
expected=[])
|
||||
])
|
||||
def validation_check(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_validation(validation_check):
|
||||
result = util.validate_json(validation_check.properties, schema)
|
||||
assert result == validation_check.expected
|
||||
@@ -23,16 +23,16 @@ commands =
|
||||
|
||||
[testenv:py27-integration]
|
||||
commands =
|
||||
py.test -vv -x {env:CI_FLAGS:} tests/integrations{posargs}
|
||||
py.test -p no:cacheprovider -vv -x {env:CI_FLAGS:} tests/integrations{posargs}
|
||||
|
||||
[testenv:py34-integration]
|
||||
commands =
|
||||
py.test -vv -x {env:CI_FLAGS:} tests/integrations{posargs}
|
||||
py.test -p no:cacheprovider -vv -x {env:CI_FLAGS:} tests/integrations{posargs}
|
||||
|
||||
[testenv:py27-unit]
|
||||
commands =
|
||||
py.test -vv {env:CI_FLAGS:} tests/unit{posargs}
|
||||
py.test -p no:cacheprovider -vv {env:CI_FLAGS:} tests/unit{posargs}
|
||||
|
||||
[testenv:py34-unit]
|
||||
commands =
|
||||
py.test -vv {env:CI_FLAGS:} tests/unit{posargs}
|
||||
py.test -p no:cacheprovider -vv {env:CI_FLAGS:} tests/unit{posargs}
|
||||
|
||||
@@ -9,7 +9,7 @@ logger = util.get_logger(__name__)
|
||||
|
||||
|
||||
def parse_json_item(json_item, schema):
|
||||
"""Parse the json item based on a schema.
|
||||
"""Parse the json item (optionally based on a schema).
|
||||
|
||||
:param json_item: A JSON item in the form 'key=value'
|
||||
:type json_item: str
|
||||
@@ -25,7 +25,13 @@ def parse_json_item(json_item, schema):
|
||||
|
||||
# Check that it is a valid key in our jsonschema
|
||||
key = terms[0]
|
||||
value = parse_json_value(key, terms[1], schema)
|
||||
|
||||
# Use the schema if we have it else, guess the type
|
||||
if schema:
|
||||
value = parse_json_value(key, terms[1], schema)
|
||||
else:
|
||||
value = _find_type(clean_value(terms[1]))
|
||||
|
||||
return (json.dumps(key), value)
|
||||
|
||||
|
||||
@@ -121,6 +127,26 @@ def clean_value(value):
|
||||
return value
|
||||
|
||||
|
||||
def _find_type(value):
|
||||
"""Find the correct type of the value
|
||||
|
||||
:param value: value to parse
|
||||
:type value: str
|
||||
:returns: The parsed value
|
||||
:rtype: int|float|
|
||||
"""
|
||||
to_try = [_parse_integer, _parse_number, _parse_boolean, _parse_array,
|
||||
_parse_url, _parse_object, _parse_string]
|
||||
while len(to_try) > 0:
|
||||
try:
|
||||
return to_try.pop(0)(value)
|
||||
except DCOSException:
|
||||
pass
|
||||
|
||||
raise DCOSException(
|
||||
'Unable to parse {!r} as a JSON object'.format(value))
|
||||
|
||||
|
||||
def _parse_string(value):
|
||||
"""
|
||||
:param value: The string to parse
|
||||
|
||||
4
tox.ini
4
tox.ini
@@ -19,8 +19,8 @@ commands =
|
||||
|
||||
[testenv:py27-unit]
|
||||
commands =
|
||||
py.test -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests
|
||||
py.test -p no:cacheprovider -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests
|
||||
|
||||
[testenv:py34-unit]
|
||||
commands =
|
||||
py.test -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests
|
||||
py.test -p no:cacheprovider -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests
|
||||
|
||||
Reference in New Issue
Block a user