def test_render_json_template_require_float_requires_float(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"muffin_count": {{ MUFFIN_COUNT|require_float }}}', ) with pytest.raises(FloatRequired): render_json_template(template_path, template_name, **{"MUFFIN_COUNT": "one muffin"})
def test_render_json_template_missing_value_raises(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"type_of_muffin": "{{ MUFFIN_TYPE }}"}', ) with pytest.raises(UndefinedError): render_json_template(template_path, template_name, **{})
def test_render_json_template_require_float_max_constraint_raises(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"muffin_count": {{ MUFFIN_COUNT|require_float(max=50) }}}', ) with pytest.raises(FloatTooLarge): render_json_template(template_path, template_name, **{"MUFFIN_COUNT": "60"})
def test_render_json_template_invalid_json_missing_value(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"type_of_muffin": {{ MUFFIN_TYPE }}}', ) with pytest.raises(InvalidJSONError): render_json_template(template_path, template_name, **{"MUFFIN_TYPE": ""})
def test_render_json_template_require_int_min_constraint_raises(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"muffin_count": {{ MUFFIN_COUNT|require_int(min=50) }}}', ) with pytest.raises(IntegerTooSmall): render_json_template(template_path, template_name, **{"MUFFIN_COUNT": "40"})
def test_render_json_template_with_inheritance_no_parent(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', ''' {% extends "bases/base.json" %} {% block MUFFIN_TYPE_PLACEHOLDER %}{{ ALT_MUFFIN_TYPE }}{% endblock %} ''', ) with pytest.raises(MissingTemplateError): render_json_template(template_path, template_name, **{})
def deploy(marathon_client, marathon_lb_client, deployment_strategy, timeout, env_prefix, template_path, template_names, force, env_pairs, **kw): """Deploy one or more applications to Marathon. """ # select the appropriate deployment strategy strategy = STRATEGIES[deployment_strategy] # use the default template if none was specified if not template_names: template_names = [strategy["default_template"]] # read and render deploy template using values from the environment values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) rendered_templates = [] for template_name in template_names: rendered_templates.append(render_json_template(template_path, template_name, **values)) # perform some extra pre-flight validation if required, and execute the # deployment, blocking until complete. deployment_params = {"marathon_client": marathon_client, "marathon_lb_client": marathon_lb_client, "timeout": timeout, "app_definitions": rendered_templates} strategy["validator"](**deployment_params) strategy["executor"](**deployment_params).execute(force)
def test_render_json_template_require_int(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"muffin_count": {{ MUFFIN_COUNT|require_int }}}', ) rendered_template = render_json_template(template_path, template_name, **{"MUFFIN_COUNT": "1"}) assert rendered_template['muffin_count'] == 1
def test_render_json_template_require_float_max_constraint(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"muffin_count": {{ MUFFIN_COUNT|require_float(max=50) }}}', ) rendered_template = render_json_template(template_path, template_name, **{"MUFFIN_COUNT": "-60"}) assert rendered_template['muffin_count'] == -60
def test_render_json_template_valid(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', '{"type_of_muffin": "{{ MUFFIN_TYPE }}"}', ) rendered_template = render_json_template(template_path, template_name, **{"MUFFIN_TYPE": "banana"}) assert "type_of_muffin" in rendered_template assert rendered_template["type_of_muffin"] == "banana"
def set(chronos_client, template_path, template_names, env_prefix, env_pairs): """Add or Update a job in chronos. """ values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) current_jobs = chronos_client.list() for template_name in template_names: rendered_template = render_json_template(template_path, template_name, **values) if _find_job(current_jobs, rendered_template['name']): chronos_client.update(rendered_template) else: chronos_client.add(rendered_template)
def cli(logger, marathon_client, env_prefix, template_path, template_names, dry_run, force, env_pairs): """Deploy application from template. """ # set dry_run param if the user has requested it. This happens in the # command callback as it only applies to the deploy command and doesn't make # sense anywhere else. marathon_client.dry_run = dry_run # read and render deploy template using values from the environment values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) rendered_templates = [] for template_name in template_names: rendered_templates.append(render_json_template(template_path, template_name, **values)) marathon_client.deploy(rendered_templates, force=force).wait()
def set(chronos_client, vault_client, template_path, template_names, env_prefix, env_pairs, **kw): """Add or Update a job in chronos. """ # use the default template if none was specified if not template_names: template_names = ["chronos/default/job.json.tmpl"] values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) current_jobs = chronos_client.list() for template_name in template_names: rendered_template = render_json_template(template_path, template_name, **values) resolved_secrets = resolve_secrets(vault_client, rendered_template) rendered_template = _inject_secrets(rendered_template, resolved_secrets) if _find_job(current_jobs, rendered_template['name']): chronos_client.update(rendered_template) else: chronos_client.add(rendered_template)
def test_render_json_template_with_inheritance_valid(tmpdir): _write_template_to_disk( tmpdir.mkdir('bases'), 'base.json', '{"type_of_muffin": "{% block MUFFIN_TYPE_PLACEHOLDER %}{{ MUFFIN_TYPE }}{% endblock %}"}', ) template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', ''' {% extends "bases/base.json" %} {% block MUFFIN_TYPE_PLACEHOLDER %}{{ ALT_MUFFIN_TYPE }}{% endblock %} ''', ) rendered_template = render_json_template(template_path, template_name, **{ "MUFFIN_TYPE": "banana", "ALT_MUFFIN_TYPE": "blueberry", }) assert "type_of_muffin" in rendered_template assert rendered_template["type_of_muffin"] == "blueberry"
def run(env_prefix, template_path, template_names, vault_client, command, env_pairs, **kw): """Run a one-off task in a "production-like" environment. Uses the current deployment configuration to start up a container locally and run a single command. Environment variables and secrets are extracted from the current deployment configuration and injected into the container when starting up. """ # use the default template if none was specified. We can just use the # standard template here since all we care about are environment variables # and secrets. if not template_names: template_name = STRATEGIES["standard"]["default_template"] else: template_name = template_names[0] # read and render deploy template using values from the environment values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) rendered_template = render_json_template(template_path, template_name, **values) # extract required configuration from the rendered template app_id = rendered_template["id"] docker_image = rendered_template["container"]["docker"]["image"] environment_variables = rendered_template["env"] environment_variables.update(resolve_secrets(vault_client, rendered_template)) logger.info("Running command for app ({0}): {1}\n".format(app_id, command)) docker_client = docker.from_env() container = docker_client.containers.run(docker_image, command, detach=True, auto_remove=True, environment=environment_variables) # stream logs from the running container to stdout for line in container.logs(stream=True): logger.info(line.decode('utf-8').rstrip()) # exit with the container's exit code once it finishes sys.exit(container.wait()['StatusCode'])
def cli(logger, marathon_client, marathon_lb_url, initial_instances, max_wait, step_interval, force, env_prefix, template_path, template_names, env_pairs): """Perform a blue/green deploy """ values = load_values_from_environment(prefix=env_prefix, overrides=env_pairs) rendered_templates = [] for template_name in template_names: rendered_templates.append(render_json_template(template_path, template_name, **values)) for app in rendered_templates: validate_app(app) # fetch all previous deploys from marathon and abort if there is more # than one stack currently active. previous_deploys = fetch_previous_deploys(marathon_client, app) if len(previous_deploys) > 1: raise DualStackAlreadyExists("Both blue and green apps detected") # transform the app to be deployed to apply the correct labels and # ID-change that will allow marathon-lb to cut traffic over as necessary. new_app = prepare_deploy(previous_deploys, app, initial_instances) logger.log('Final App Definition:') logger.log(json.dumps(new_app, indent=4, sort_keys=True)) if force or click.confirm("Continue with deployment?"): try: deploy_and_swap(marathon_client, new_app, previous_deploys, logger, force, max_wait, step_interval, initial_instances, marathon_lb_url) except (DeploymentFailed, SwapApplicationTimeout): remove_new_stack(marathon_client, logger, app['id'], force)
def test_render_json_template_all_env(tmpdir): template_path, template_name = _write_template_to_disk( tmpdir, 'template.json', ''' { "types_of_muffin": { {% for k, v in _all_env|filter_items("MUFFIN_", True) %} "{{ k.lower() }}": {{ v }}{% if loop.last == False %},{% endif %} {% endfor %} } } ''', ) rendered_template = render_json_template(template_path, template_name, **{ "MUFFIN_BLUEBERRY": 4, "MUFFIN_BANANA": 7, "MUFFIN_CHOCOLATE": 12, "DONUT_STRAWBERRY": 9, }) assert "types_of_muffin" in rendered_template assert rendered_template["types_of_muffin"]["blueberry"] == 4 assert rendered_template["types_of_muffin"]["banana"] == 7 assert rendered_template["types_of_muffin"]["chocolate"] == 12