{ "info": { "author": "Jamie Hewland", "author_email": "jamie@praekelt.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Framework :: Twisted", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy" ], "description": "marathon-acme\n=============\n\n|PyPI| |Build Status| |codecov|\n\nAutomate\n`ACME `__\ncertificates for `Marathon `__\napps served by\n`marathon-lb `__\n\nHow it works\n------------\n\nThere is one big requirement for deploying ``marathon-acme``: there must\nbe shared persistent storage between ``marathon-acme`` and all\n``marathon-lb`` instances. This will be used to store the certificates.\n\n1. ``marathon-acme`` watches Marathon for changes to app definitions.\n2. It collects the values of all ``MARATHON_ACME_{n}_DOMAIN`` labels on\n apps. This will form the set of domains to fetch certificates for.\n3. It generates, verifies and stores certificates for any new domains\n using the configured ACME certificate authority.\n4. It tells ``marathon-lb`` to reload using the ``marathon-lb`` HTTP\n API.\n5. It issues new certificates for soon-to-expire certificates once a\n day.\n\n``marathon-acme`` is written in Python using\n`Twisted `__. The certificate issuing\nfunctionality is possible thanks to the\n`txacme `__ library.\n\nThe ACME provider that most people are likely to use is `Let's\nEncrypt `__. Before using ``marathon-acme``\nwith Let's Encrypt, make sure you are aware of their `rate\nlimits `__.\n\nThe entire certificate-issuing workflow is shown below:\n\n.. image:: issue-certificate.svg\n\nUsage\n-----\n\n``marathon-acme`` is available as a pip-installable Python package on\n`PyPI `__. However, most\nusers will probably want to use the Docker image available from `Docker\nHub `__.\n\n::\n\n > $ docker run --rm praekeltfoundation/marathon-acme --help\n usage: marathon-acme [-h] [-a ACME] [-e EMAIL] [-m MARATHON[,MARATHON,...]]\n [-l LB[,LB,...]] [-g GROUP] [--allow-multiple-certs]\n [--listen LISTEN] [--sse-timeout SSE_TIMEOUT]\n [--log-level {debug,info,warn,error,critical}]\n storage-dir\n\n Automatically manage ACME certificates for Marathon apps\n\n positional arguments:\n storage-dir Path to directory for storing certificates\n\n optional arguments:\n -h, --help show this help message and exit\n -a ACME, --acme ACME The address for the ACME Directory Resource (default:\n https://acme-v01.api.letsencrypt.org/directory)\n -e EMAIL, --email EMAIL\n An email address to register with the ACME service\n (optional)\n -m MARATHON[,MARATHON,...], --marathon MARATHON[,MARATHON,...]\n The addresses for the Marathon HTTP API (default:\n http://marathon.mesos:8080)\n -l LB[,LB,...], --lb LB[,LB,...]\n The addresses for the marathon-lb HTTP API (default:\n http://marathon-lb.marathon.mesos:9090)\n -g GROUP, --group GROUP\n The marathon-lb group to issue certificates for\n (default: external)\n --allow-multiple-certs\n Allow multiple certificates for a single app port.\n This allows multiple domains for an app, but is not\n recommended.\n --listen LISTEN The address for the port to listen on (default: :8000)\n --sse-timeout SSE_TIMEOUT\n Amount of time in seconds to wait for some event data\n to be received from Marathon. Set to 0 to disable.\n (default: 60)\n --log-level {debug,info,warn,error,critical}\n The minimum severity level to log messages at\n (default: info)\n --version show program's version number and exit\n\n``marathon-acme`` app definition\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``marathon-acme`` should be deployed as a Marathon app.\n\n.. code:: json\n\n {\n \"id\": \"/marathon-acme\",\n \"cpus\": 0.01,\n \"mem\": 128.0,\n \"args\": [\n \"--email\", \"letsencrypt@example.com\",\n \"--marathon\", \"http://marathon1:8080,http://marathon2:8080,http://marathon3:8080\",\n \"--lb\", \"http://lb1:9090,http://lb2:9090\",\n \"/var/lib/marathon-acme\"\n ],\n \"labels\": {\n \"HAPROXY_GROUP\": \"external\",\n \"HAPROXY_0_VHOST\": \"marathon-acme.example.com\",\n \"HAPROXY_0_BACKEND_WEIGHT\": \"1\",\n \"HAPROXY_0_PATH\": \"/.well-known/acme-challenge/\",\n \"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH\": \" acl host_{cleanedUpHostname} hdr(host) -i {hostname}\\n acl path_{backend} path_beg {path}\\n redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend}\\n use_backend {backend} if host_{cleanedUpHostname} path_{backend}\\n\"\n },\n \"container\": {\n \"type\": \"DOCKER\",\n \"docker\": {\n \"image\": \"praekeltfoundation/marathon-acme\",\n \"network\": \"BRIDGE\",\n \"portMappings\": [\n { \"containerPort\": 8000, \"hostPort\": 0 }\n ],\n \"parameters\": [\n {\n \"value\": \"my-volume-driver\",\n \"key\": \"volume-driver\"\n },\n {\n \"value\": \"marathon-acme-certs:/var/lib/marathon-acme\",\n \"key\": \"volume\"\n }\n ],\n }\n }\n }\n\nThe above should mostly be standard across different deployments. The\nvolume parameters will depend on your particular networked storage\nsolution.\n\n``HAPROXY`` labels\n^^^^^^^^^^^^^^^^^^\n\n.. code:: json\n\n \"labels\": {\n \"HAPROXY_GROUP\": \"external\",\n \"HAPROXY_0_VHOST\": \"marathon-acme.example.com\",\n \"HAPROXY_0_BACKEND_WEIGHT\": \"1\",\n \"HAPROXY_0_PATH\": \"/.well-known/acme-challenge/\",\n \"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH\": \" acl host_{cleanedUpHostname} hdr(host) -i {hostname}\\n acl path_{backend} path_beg {path}\\n redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend}\\n use_backend {backend} if host_{cleanedUpHostname} path_{backend}\\n\"\n }\n\nSeveral special ``marathon-lb`` labels are needed in order to forward\nall HTTP requests whose path begins with\n``/.well-known/acme-challenge/`` to ``marathon-acme``, in order to serve\nACME `HTTP\nchallenge `__\nresponses.\n\n``HAPROXY_GROUP``\n'''''''''''''''''\n\n::\n\n external\n\n``marathon-lb`` instances are assigned a group. Only Marathon apps with\na ``HAPROXY_GROUP`` label that matches their group are routed with that\ninstance. \"external\" is the common name for publicly-facing load\nbalancers.\n\n``HAPROXY_0_VHOST``\n'''''''''''''''''''\n\n::\n\n marathon-acme.example.com\n\n``marathon-acme`` needs its own domain to respond to ACME challenge\nrequests on. This domain must resolve to your ``marathon-lb``\ninstance(s).\n\n``HAPROXY_0_BACKEND_WEIGHT``\n''''''''''''''''''''''''''''\n\n::\n\n 1\n\nWe want this rule in HAProxy's config file to come before any others so\nthat requests are routed to ``marathon-acme`` before we do the (usually)\ndomain-based routing for the other Marathon apps. The default weight is\n``0``, so we set to ``1`` so that the rule comes first.\n\n``HAPROXY_0_PATH``\n''''''''''''''''''\n\n::\n\n /.well-known/acme-challenge/\n\nThis is the beginning of the HTTP path to ACME validation challenges.\n\n``HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH``\n'''''''''''''''''''''''''''''''''''''''''\n\n::\n\n acl host_{cleanedUpHostname} hdr(host) -i {hostname}\n acl path_{backend} path_beg {path}\n redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend}\n use_backend {backend} if host_{cleanedUpHostname} path_{backend}\n\nThis is where it gets complicated... It\u2019s possible to edit the templates\nused for generating the HAProxy on a per-app basis using labels. This is\nnecessary because by default ``marathon-lb`` will route based on domain\nfirst, but we don\u2019t want to do that. You can see the standard template\n`here `__.\n\nHere, we add an extra ``redirect`` rule. This redirects all requests\nmatching the ACME challenge path to ``marathon-acme``, except those\nrequests already headed for ``marathon-acme``. The Let's Encrypt server\nwill follow redirects.\n\n``HAPROXY`` HTTPS labels\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nIt is possible to have ``marathon-acme`` serve ACME challenge requests\nover HTTPS, although this is usually not necessary. In this case, a\ncertificate needs to be issued for ``marathon-acme`` and the HTTP\nredirect label needs to be modified:\n\n.. code:: json\n\n \"labels\": {\n ...,\n \"MARATHON_ACME_0_DOMAIN\": \"marathon-acme.example.com\",\n \"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH\": \" acl host_{cleanedUpHostname} hdr(host) -i {hostname}\\n acl path_{backend} path_beg {path}\\n redirect prefix https://{hostname} code 302 if path_{backend}\\n\"\n }\n\nNote that using the ``HAPROXY_0_REDIRECT_TO_HTTPS`` label for\n``marathon-acme`` will break things. This label is difficult for us to\nuse because of the way ``marathon-lb``'s templating works.\n\n``MARATHON_ACME_0_DOMAIN``\n''''''''''''''''''''''''''\n\n::\n\n marathon-acme.example.com\n\nHere we set up ``marathon-acme`` to fetch a certificate for itself.\n\n``HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH``\n'''''''''''''''''''''''''''''''''''''''''\n\n::\n\n acl host_{cleanedUpHostname} hdr(host) -i {hostname}\n acl path_{backend} path_beg {path}\n redirect prefix https://{hostname} code 302 if path_{backend}\n\nWe redirect to the HTTPS address (``https://{hostname}``) for all\ndomains (including ``marathon-acme``'s) for requests to the ACME\nchallenge path. The ``use_backend`` directive can now be removed since\nthe backend is never used over HTTP as all requests are redirected.\n\n**Note that this label can only be set after marathon-acme has\nfetched the first certificate for its own domain.** In other words, set\nthe ``MARATHON_ACME_0_DOMAIN`` *first* and make sure it has taken effect\nbefore setting this one.\n\nDocker images\n^^^^^^^^^^^^^\n\nDocker images are available from `Docker\nHub `__.\nThere are two different streams of Docker images available:\n\n- ``:latest``/``:``: Tracks the latest released version of\n ``marathon-acme`` on `PyPI `__.\n The Dockerfile for these is in the `praekeltfoundation/docker-marathon-acme\n `__ repo.\n- ``:develop``: Tracks the ``develop`` branch of this repo and is built\n using the `Dockerfile `__ in this repo.\n\nFor more details on the Docker images, see the\n`praekeltfoundation/docker-marathon-acme `__\nrepo.\n\nVolumes and ports\n'''''''''''''''''\n\nThe ``marathon-acme`` container defaults to the\n``/var/lib/marathon-acme`` directory to store certificates and the ACME\nclient private key. This is the path inside the container that should be\nmounted as a shared volume.\n\nThe container also defaults to listening on port 8000 on all interfaces.\n\nYou can override these values by providing arguments to the Docker\ncontainer.\n\nCertificate files\n^^^^^^^^^^^^^^^^^\n\n``marathon-acme`` creates the following directory/file structure:\n\n- ``/var/lib/marathon-acme/``\n\n - ``client.key``: The ACME client private key\n - ``default.pem``: A self-signed wildcard cert for HAProxy to fallback to\n - ``certs/``\n\n - *www.example.com.pem*: An issued ACME certificate for a domain\n\n - ``unmanaged-certs/``: A directory for certs that ``marathon-acme``\n doesn't manage\n\n``marathon-acme`` does nothing with the ``unmanaged-certs/`` directory\nafter creating it. HAProxy fails if any path in its certificate config\ndoesn't exist, so it reduces setup friction to have a standard place to\nput unmanaged certificates.\n\n``marathon-lb`` configuration\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``marathon-acme`` requires ``marathon-lb`` 1.4.0 or later in order to be\nable to trigger HAProxy reloads.\n\nAs mentioned earlier, ``marathon-lb`` must share persistent storage with\n``marathon-acme``. BYONS: *bring your own networked storage.*\n\nThe only real configuration needed for ``marathon-lb`` is to add the\npath to ``marathon-acme``'s certificate storage directory as a source of\ncertificates. HAProxy supports loading certificates from a directory.\nYou should set ``marathon-lb``'s ``--ssl-certs`` CLI option to the\ncertificate directory path as well as the fallback certificate (if\nHAProxy cannot find any certificates in the paths it is given it will\nfail to start).\n\n::\n\n --ssl-certs /certs,/default.pem\n\nApp configuration\n~~~~~~~~~~~~~~~~~\n\n``marathon-acme`` uses a single ``marathon-lb``-like label to assign\ndomains to app ports: ``MARATHON_ACME_{n}_DOMAIN``, where ``{n}`` is the\nport index. The value of the label is a set of comma- and/or\nwhitespace-separated domain names, although **by default only the first\ndomain name will be considered**.\n\nCurrently, ``marathon-acme`` can only issue certificates with a single\ndomain. This means multiple certificates need to be issued for apps with\nmultiple configured domains.\n\nA limitation was added that limits apps to a single domain. This limit\ncan be removed by passing the ``--allow-multiple-certs`` command-line\noption, although this is not recommended as it makes it possible for a\nlarge number of certificates to be issued for a single app, potentially\nexhausting the Let's Encrypt rate limit.\n\nThe app or its port must must be in the same ``HAPROXY_GROUP`` as\n``marathon-acme`` was configured with at start-up.\n\nWe decided not to reuse the ``HAPROXY_{n}_VHOST`` label so as to limit\nthe number of domains that certificates are issued for.\n\nLimitations\n-----------\n\nThe library used for ACME certificate management, ``txacme``, is\ncurrently quite limited in its functionality. The two biggest\nlimitations are:\n\n- There is no `Subject Alternative Name\n `__ (SAN) support\n yet (`#37 `__). Each\n certificate will correspond to exactly one domain name. This limitation\n makes it easier to hit Let's Encrypt's rate limits.\n- There is no support for *removing* certificates from ``txacme``'s\n certificate store (`#77 `__).\n Once ``marathon-acme`` issues a certificate for an app it will try to renew\n that certificate *forever* unless it is manually deleted from the\n certificate store.\n\nFor a more complete list of issues, see the issues page for this repo.\n\nTroubleshooting\n---------------\n\nChallenge ping endpoint\n~~~~~~~~~~~~~~~~~~~~~~~\n\nOne common problem is that ``marathon-lb`` is misconfigured and ACME\nchallenge requests are unable to reach ``marathon-acme``. You can test\nchallenge request routing to ``marathon-acme`` using the challenge ping\nendpoint.\n\nIt should be possible to reach the ``/.well-known/acme-challenge/ping``\npath from all domains served by ``marathon-lb``:\n\n::\n\n > $ curl cake-service.example.com/.well-known/acme-challenge/ping\n {\"message\": \"pong\"}\n\n > $ curl soda-service.example.com/.well-known/acme-challenge/ping\n {\"message\": \"pong\"}\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/marathon-acme.svg\n :target: https://pypi.python.org/pypi/marathon-acme\n.. |Build Status| image:: https://travis-ci.org/praekeltfoundation/marathon-acme.svg?branch=develop\n :target: https://travis-ci.org/praekeltfoundation/marathon-acme\n.. |codecov| image:: https://codecov.io/gh/praekeltfoundation/marathon-acme/branch/develop/graph/badge.svg\n :target: https://codecov.io/gh/praekeltfoundation/marathon-acme\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/praekeltfoundation/marathon-acme", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "marathon-acme", "package_url": "https://pypi.org/project/marathon-acme/", "platform": "", "project_url": "https://pypi.org/project/marathon-acme/", "project_urls": { "Homepage": "https://github.com/praekeltfoundation/marathon-acme" }, "release_url": "https://pypi.org/project/marathon-acme/0.6.1/", "requires_dist": [ "acme (>=0.21.0)", "cryptography", "josepy", "klein", "requests", "treq (>=17.3.1)", "Twisted[tls]", "txacme (>=0.9.2)", "uritools (>=1.0.0)", "flake8; extra == 'pep8test'", "flake8-import-order; extra == 'pep8test'", "fixtures; extra == 'test'", "pem (>=16.1.0); extra == 'test'", "pytest (>=3.0.0); extra == 'test'", "testtools; extra == 'test'", "txfake (>=0.1.1); extra == 'test'" ], "requires_python": "", "summary": "Automated management of Let's Encrypt certificates for apps running on Mesosphere Marathon", "version": "0.6.1" }, "last_serial": 4006949, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "2fb62b4dde7c85e1af28e4a8240e11a2", "sha256": "9f4290f4f06fa5c1adf2baa5918612cd74b74f66c3adf9af19af62abf93e5c28" }, "downloads": -1, "filename": "marathon_acme-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "2fb62b4dde7c85e1af28e4a8240e11a2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 51816, "upload_time": "2016-12-13T13:11:28", "url": "https://files.pythonhosted.org/packages/02/c6/03e5e62f5be74a5f000721d3c84a6517ce25816da14832c4e869d683eadb/marathon_acme-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "65a24918fd9d3b4804a8454adb17abb6", "sha256": "7860293e3394d7ec9470c25042d722ffbf02b393e139ae9ae43c48c0ca76eb9e" }, "downloads": -1, "filename": "marathon-acme-0.1.0.tar.gz", "has_sig": false, "md5_digest": "65a24918fd9d3b4804a8454adb17abb6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 41128, "upload_time": "2016-12-13T13:09:22", "url": "https://files.pythonhosted.org/packages/7e/37/28cfb02a243537336a4a4af4bdb679503bff04edc1414144049b7103198a/marathon-acme-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "d13ca86ab6329b419ca20ffe5fc3f1f9", "sha256": "fc092c369535644db2a1a3a178d6010a16b51487bd729c03b40848a51aa44f87" }, "downloads": -1, "filename": "marathon_acme-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d13ca86ab6329b419ca20ffe5fc3f1f9", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 51770, "upload_time": "2017-06-12T12:29:00", "url": "https://files.pythonhosted.org/packages/6a/1f/3ff748f1b4fe3f42d59a8ab9fab7bede1e5c6df2c140b5d9d28922718eea/marathon_acme-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0bd4aeb81084fa607869ef2dce76cab1", "sha256": "00fa5dfbd223bfccc09c739677296b258c44516e2b3e2d56ff5d2f99acd5551f" }, "downloads": -1, "filename": "marathon-acme-0.1.1.tar.gz", "has_sig": false, "md5_digest": "0bd4aeb81084fa607869ef2dce76cab1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 42718, "upload_time": "2017-06-12T12:29:02", "url": "https://files.pythonhosted.org/packages/58/90/02701ef62efeeee66f1d0fce2f0c117a3d65654729752062fd6adb1c54af/marathon-acme-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "f0c7ab892e84205612edfbd9892153a6", "sha256": "8e36f5751da6a812b13449530f56c9ef07d296780ea6e5ee9c1a1fed7f5d85e6" }, "downloads": -1, "filename": "marathon_acme-0.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f0c7ab892e84205612edfbd9892153a6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 54192, "upload_time": "2017-06-27T15:16:49", "url": "https://files.pythonhosted.org/packages/37/7e/6dcce8e2f1b065f0120afc8de50f0d0edfd20c2e1acabb0beb984faebb1a/marathon_acme-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c75fa31de64880ac1ff4fe7f4a2adf1d", "sha256": "f8778d60c1f6fd5a3ea20b397906ce66d32b7eb1825b2dd8a0052006394b054d" }, "downloads": -1, "filename": "marathon-acme-0.2.0.tar.gz", "has_sig": false, "md5_digest": "c75fa31de64880ac1ff4fe7f4a2adf1d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 41924, "upload_time": "2017-06-27T15:16:51", "url": "https://files.pythonhosted.org/packages/b1/b3/6eeddf2240c0524d1d1fd54de65aa3fd6a1f6611fe3576c59f679e3f0035/marathon-acme-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "44ab56a89369dc3e4183dbae4678083d", "sha256": "d70dacdb5f68a59547e048fab9d736551f1b8c6d4687e4c7f9ddd9778ac9e7d4" }, "downloads": -1, "filename": "marathon_acme-0.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "44ab56a89369dc3e4183dbae4678083d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55979, "upload_time": "2017-09-01T10:47:57", "url": "https://files.pythonhosted.org/packages/22/15/173c1bb688caf291a90974268dbbb233c577ed2b439e3b60f58aa6867e89/marathon_acme-0.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8d0a9167c843ec2162ca601902d212b4", "sha256": "41a4b8d228cddbff24087a98696d01c6fdd91bf8f0b6a88db523907de9fc5466" }, "downloads": -1, "filename": "marathon-acme-0.3.0.tar.gz", "has_sig": false, "md5_digest": "8d0a9167c843ec2162ca601902d212b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 43286, "upload_time": "2017-09-01T10:47:59", "url": "https://files.pythonhosted.org/packages/58/83/d375b2fb8a3c543c6505f9216f50b0662c16395a2f4052d613cbe10e8367/marathon-acme-0.3.0.tar.gz" } ], "0.3.0.1": [ { "comment_text": "", "digests": { "md5": "bac8d12e902d86997dec51ad88199d81", "sha256": "54fbac94e94454eef596b702ee844f9d9e72db50c07ea6a0de7190afd14eb8b4" }, "downloads": -1, "filename": "marathon_acme-0.3.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bac8d12e902d86997dec51ad88199d81", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 56454, "upload_time": "2017-09-01T11:53:01", "url": "https://files.pythonhosted.org/packages/9e/95/2a83e616cfc60b26566e1b8ee57c968f926aeade7a6a55f16d26c2f7d5e3/marathon_acme-0.3.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e970ef66abe390dc334808ecaebc6978", "sha256": "05dd3bedbbcd28dd1156605a309487871f38e970ac8f2bab45588c488c19c988" }, "downloads": -1, "filename": "marathon-acme-0.3.0.1.tar.gz", "has_sig": false, "md5_digest": "e970ef66abe390dc334808ecaebc6978", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46625, "upload_time": "2017-09-01T11:53:03", "url": "https://files.pythonhosted.org/packages/f8/13/21149ee46514249a4e093cefe90a69a0bad49b1c336f09af1886f38c8d1c/marathon-acme-0.3.0.1.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "876ab93e863edd375285452bb24e0ebb", "sha256": "da09335885b1bc4e8910eea3fc5c8917c4c8a850cfb99581aec0c49917c8ec26" }, "downloads": -1, "filename": "marathon_acme-0.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "876ab93e863edd375285452bb24e0ebb", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 56628, "upload_time": "2017-09-04T13:22:58", "url": "https://files.pythonhosted.org/packages/4a/7b/c3b84e8f41803203bd1c98f402e63732cc2ac6f5e444987f50445b6bf7ca/marathon_acme-0.3.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8b73621c022038b2e56eb32eef48463b", "sha256": "0291299685fb6faf9c8a75855e127dc07e01b31075cff87e88443088fc85f7e4" }, "downloads": -1, "filename": "marathon-acme-0.3.1.tar.gz", "has_sig": false, "md5_digest": "8b73621c022038b2e56eb32eef48463b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46863, "upload_time": "2017-09-04T13:22:59", "url": "https://files.pythonhosted.org/packages/b4/9a/af4e13331b4a87aeda098bde28c4c9e1756eb54322bb6713fab4102138b5/marathon-acme-0.3.1.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "f0733366dc4ffac3e0bb07c8c6f03570", "sha256": "bdedb47ae9d87862665f86e81cbc2a324eb594be5a420eb72a989552fc14c7e7" }, "downloads": -1, "filename": "marathon_acme-0.4.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f0733366dc4ffac3e0bb07c8c6f03570", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 57810, "upload_time": "2017-10-05T08:32:23", "url": "https://files.pythonhosted.org/packages/de/37/b9f328237018c3b839af7a55569cc302e80f46b69ceb9bbdaf48c9bcc315/marathon_acme-0.4.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b925cc847a47174290d5b396fcd7bb43", "sha256": "4a2f0900f1ab6a469b05768c7cb8324790c0d07798fa09ab70357ecf4ff16af8" }, "downloads": -1, "filename": "marathon-acme-0.4.0.tar.gz", "has_sig": false, "md5_digest": "b925cc847a47174290d5b396fcd7bb43", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 47950, "upload_time": "2017-10-05T08:32:24", "url": "https://files.pythonhosted.org/packages/9a/35/c5c9a9b5c813992f7e5d3ec2c8f7d29e09d9dc25942a9d3779d9ea409c26/marathon-acme-0.4.0.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "f4447862d06239f760f6e21a8f1600e5", "sha256": "e54c55f1586d9aba942f267302dfc9c37bed93e6d95614ef461d4794287a694d" }, "downloads": -1, "filename": "marathon_acme-0.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f4447862d06239f760f6e21a8f1600e5", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 59492, "upload_time": "2017-11-29T15:11:20", "url": "https://files.pythonhosted.org/packages/58/b2/326c7b5735d2932c94f1bbcb2331bd1f748a38cc3ca8729f23c8b70e2d53/marathon_acme-0.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e93cb9dc1f2460d2e64b6e5549801e6f", "sha256": "f6154aa0d3a7bc2778bc17e4b668e8af2b6ea17beb5f1dae6d68638683714570" }, "downloads": -1, "filename": "marathon-acme-0.5.0.tar.gz", "has_sig": false, "md5_digest": "e93cb9dc1f2460d2e64b6e5549801e6f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49570, "upload_time": "2017-11-29T15:11:21", "url": "https://files.pythonhosted.org/packages/19/9a/91788253a8a70c8e7ae35754be611f11fa5b8435a3a91a646fe8b838c6c0/marathon-acme-0.5.0.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "1e27b4c266dc7911aeb2028dd17cadc3", "sha256": "ad23e094e1479d1a4724264200441d275ad14ffef17c32290b695b7e3fcda752" }, "downloads": -1, "filename": "marathon_acme-0.5.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1e27b4c266dc7911aeb2028dd17cadc3", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 59383, "upload_time": "2017-12-07T12:53:37", "url": "https://files.pythonhosted.org/packages/fb/70/787cdc2d0ce92820c1fe4e3646b60e6c4d06df9ffb2c491518acfb7b924d/marathon_acme-0.5.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6df033e74f14147b8ec49e3c1d951b30", "sha256": "1f99517e67fad9b2671c4fa6190264f5c44c787c94b654054ddf2a2685c065d5" }, "downloads": -1, "filename": "marathon-acme-0.5.1.tar.gz", "has_sig": false, "md5_digest": "6df033e74f14147b8ec49e3c1d951b30", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49398, "upload_time": "2017-12-07T12:53:38", "url": "https://files.pythonhosted.org/packages/da/9b/40418012cc159216c8860a502d3a13ab1f1f9c573908c91d8b8b4495e406/marathon-acme-0.5.1.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "38df2d84e7782ed08d755ea55507fdfa", "sha256": "d29450bcea54768b6f671c70b87d56b2763cf5701ccaa3b6b2404e53edc9405f" }, "downloads": -1, "filename": "marathon_acme-0.6.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "38df2d84e7782ed08d755ea55507fdfa", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 59775, "upload_time": "2018-02-01T12:55:23", "url": "https://files.pythonhosted.org/packages/37/ed/8e7a52fc3d14c1ff3afa7a1f1ec4f10e190111643890d5466d9d602d3a22/marathon_acme-0.6.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "de821a03218bcd2743f5a12c9670562f", "sha256": "2c1cf9acea5776d5927c15989fb16bdcf01f645e22051742a0e75fd2f3e2beb6" }, "downloads": -1, "filename": "marathon-acme-0.6.0.tar.gz", "has_sig": false, "md5_digest": "de821a03218bcd2743f5a12c9670562f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49790, "upload_time": "2018-02-01T12:55:25", "url": "https://files.pythonhosted.org/packages/49/a4/83b5cbcf12e6c03dfb5843030ec995ef9f8992415037a1a12519e3be6f6a/marathon-acme-0.6.0.tar.gz" } ], "0.6.1": [ { "comment_text": "", "digests": { "md5": "0a7d9691b1a772922529653f863c858b", "sha256": "01d7d74e22931206436ef2ad0147e1b8eed3ff8177b7f9db48e17f4cdf34ef0c" }, "downloads": -1, "filename": "marathon_acme-0.6.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "0a7d9691b1a772922529653f863c858b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 54118, "upload_time": "2018-06-27T11:31:48", "url": "https://files.pythonhosted.org/packages/71/54/d9f1dd09c691a69a1956e752f31e93965375fbfa23634e721d5def4d10df/marathon_acme-0.6.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b5457854dedc36cc7e6bff3e7c6cfd4f", "sha256": "c001e77101a0f63b16ee5e36cbf8d628e6dc3c35281d38dd5f9c264a6d901bc3" }, "downloads": -1, "filename": "marathon-acme-0.6.1.tar.gz", "has_sig": false, "md5_digest": "b5457854dedc36cc7e6bff3e7c6cfd4f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 198070, "upload_time": "2018-06-27T11:31:50", "url": "https://files.pythonhosted.org/packages/82/a0/c37cbb0810245ffbf03fc052daa1cddb97994b86ee9ed962b49cdaa031fe/marathon-acme-0.6.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0a7d9691b1a772922529653f863c858b", "sha256": "01d7d74e22931206436ef2ad0147e1b8eed3ff8177b7f9db48e17f4cdf34ef0c" }, "downloads": -1, "filename": "marathon_acme-0.6.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "0a7d9691b1a772922529653f863c858b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 54118, "upload_time": "2018-06-27T11:31:48", "url": "https://files.pythonhosted.org/packages/71/54/d9f1dd09c691a69a1956e752f31e93965375fbfa23634e721d5def4d10df/marathon_acme-0.6.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b5457854dedc36cc7e6bff3e7c6cfd4f", "sha256": "c001e77101a0f63b16ee5e36cbf8d628e6dc3c35281d38dd5f9c264a6d901bc3" }, "downloads": -1, "filename": "marathon-acme-0.6.1.tar.gz", "has_sig": false, "md5_digest": "b5457854dedc36cc7e6bff3e7c6cfd4f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 198070, "upload_time": "2018-06-27T11:31:50", "url": "https://files.pythonhosted.org/packages/82/a0/c37cbb0810245ffbf03fc052daa1cddb97994b86ee9ed962b49cdaa031fe/marathon-acme-0.6.1.tar.gz" } ] }