Skip to content

Commit

Permalink
Merge pull request #14 from wcm-io-devops/feature/custom-port-support
Browse files Browse the repository at this point in the history
Allow custom ports and binding IP adresses, move main logic to action_plugins
  • Loading branch information
tobias-richter authored Dec 6, 2019
2 parents 9eaa0d0 + 1cfc83c commit 5c38cd3
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 125 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ npm-debug.log
*.sublime-*
*nbactions*.xml
.temp/
*.pyc
124 changes: 124 additions & 0 deletions action_plugins/conga_aemdst_facts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)

__metaclass__ = type

from ansible.plugins.action import ActionBase
from ansible.errors import AnsibleOptionsError

try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display

display = Display()


class ActionModule(ActionBase):
TRANSFERS_FILES = False

def __init__(self, task, connection, play_context, loader, templar, shared_loader_obj):
super(ActionModule, self).__init__(task, connection, play_context, loader, templar, shared_loader_obj)
self._task_vars = None

def run(self, tmp=None, task_vars=None):
if task_vars is None:
task_vars = dict()

result = super(ActionModule, self).run(tmp, task_vars)

self._task_vars = task_vars

try:
# Get conga_facts based config (whole or tenant config)
config = self._get_arg_or_var('conga_config')

except AnsibleOptionsError as err:
return self._fail_result(result, err.message)

httpd_cfg = config.get("httpd", {})
ssl_cfg = httpd_cfg.get("ssl", {})
ssl_enforce = ssl_cfg.get("enforce", False)

ssl_offloading_cfg = ssl_cfg.get("offloading", {})
ssl_offloading_enabled = ssl_offloading_cfg.get("enabled", False)

# set defaults
server_listen_address = httpd_cfg.get("serverListenAddressSsl", "127.0.0.1")
server_listen_address_ssl = httpd_cfg.get("serverListenAddressSsl", "127.0.0.1")

if server_listen_address == "*":
server_listen_address = "127.0.0.1"

if server_listen_address_ssl == "*":
server_listen_address_ssl = "127.0.0.1"

server_name = httpd_cfg.get("serverName", None)
server_name_ssl = httpd_cfg.get("serverNameSsl", None)

listen_port = httpd_cfg.get("serverPort", 80)
listen_port_ssl = httpd_cfg.get("serverPortSsl", 443)

initial_port = listen_port
expected_port = listen_port

response_test_headers = []

# when ssl is enforced and not offloaded we are expecting the ssl port
if ssl_enforce and not ssl_offloading_enabled:
expected_port = listen_port_ssl

listen_port_suffix = "" if listen_port == 80 else ":{}".format(initial_port)
listen_port_suffix_ssl = "" if listen_port_ssl == 443 else ":{}".format(expected_port)

ssl_enforce_initial_url = "http://{}{}".format(server_name, listen_port_suffix)
ssl_enforce_expected_url = "https://{}{}/".format(server_name_ssl, listen_port_suffix_ssl)

response_test_initial_url = ssl_enforce_initial_url
response_test_expected_url = response_test_initial_url + "/"

if ssl_enforce:
if ssl_offloading_enabled:
# when ssl is offloaded we have to simulate a forwareded https request
response_test_headers.append("X-Forwarded-Proto: https")
else:
# when ssl is not offloaded we are expecting an ssl upgrade
response_test_expected_url = ssl_enforce_expected_url

results = {
# "config": config,
"server_listen_address": server_listen_address,
"server_listen_address_ssl": server_listen_address_ssl,
"listen_port": listen_port,
"listen_port_ssl": listen_port_ssl,
"initial_port": initial_port,
"expected_port": expected_port,
"listen_port_suffix": listen_port_suffix,
"listen_port_suffix_ssl": listen_port_suffix_ssl,
"ssl_enforce_initial_url": ssl_enforce_initial_url,
"ssl_enforce_expected_url": ssl_enforce_expected_url,
"response_test_headers": response_test_headers,
"response_test_initial_url": response_test_initial_url,
"response_test_expected_url": response_test_expected_url
}

result["ansible_facts"] = {
"conga_aemdst_config": results,
}

return result

@staticmethod
def _fail_result(result, message):
result['failed'] = True
result['msg'] = message
return result

def _get_arg_or_var(self, name, default=None, is_required=True):
ret = self._task.args.get(name, self._task_vars.get(name, default))
if is_required and not ret:
raise AnsibleOptionsError("parameter %s is required" % name)
else:
return ret
110 changes: 110 additions & 0 deletions action_plugins/curl_cmdline_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)

__metaclass__ = type

from ansible.plugins.action import ActionBase
from ansible.errors import AnsibleOptionsError

try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display

display = Display()


class ActionModule(ActionBase):
TRANSFERS_FILES = False

def __init__(self, task, connection, play_context, loader, templar, shared_loader_obj):
super(ActionModule, self).__init__(task, connection, play_context, loader, templar, shared_loader_obj)
self._task_vars = None
self._templar = templar

def run(self, tmp=None, task_vars=None):
if task_vars is None:
task_vars = dict()

result = super(ActionModule, self).run(tmp, task_vars)

self._task_vars = task_vars

try:
# Get config values
conga_aemdst_curl_url = self._get_arg_or_var('conga_aemdst_curl_url')
conga_aemdst_curl_expected_http_code = self._get_arg_or_var('conga_aemdst_curl_expected_http_code')
conga_aemdst_curl_follow_redirects_expected_http_code = self._get_arg_or_var('conga_aemdst_curl_follow_redirects_expected_http_code')
conga_aemdst_curl_follow_redirects = self._get_arg_or_var('conga_aemdst_curl_follow_redirects')
conga_aemdst_curl_allow_insecure = self._get_arg_or_var('conga_aemdst_curl_allow_insecure')
conga_aemdst_curl_noproxy = self._get_arg_or_var('conga_aemdst_curl_noproxy')
conga_aemdst_curl_resolve = self._get_arg_or_var('conga_aemdst_curl_resolve', [], False)
conga_aemdst_curl_headers = self._get_arg_or_var('conga_aemdst_curl_headers', [], False)
conga_aemdst_curl_timeout = self._get_arg_or_var('conga_aemdst_curl_timeout')
conga_aemdst_curl_connect_timeout = self._get_arg_or_var('conga_aemdst_curl_connect_timeout')

except AnsibleOptionsError as err:
return self._fail_result(result, err.message)

# set defaults
curl_cmdline_args = [
'--max-time {}'.format(conga_aemdst_curl_timeout),
'--connect-timeout {}'.format(conga_aemdst_curl_connect_timeout),
]
write_out_arg = "%{redirect_url}\n%{http_code}"
expected_http_code = conga_aemdst_curl_expected_http_code

if conga_aemdst_curl_allow_insecure:
curl_cmdline_args.append('--insecure')

for resolve in conga_aemdst_curl_resolve:
host = resolve.get("host")
port = resolve.get("port")
address = resolve.get("address")
curl_cmdline_args.append("--resolve '{}:{}:{}'".format(host, port, address))

if conga_aemdst_curl_follow_redirects:
curl_cmdline_args.append('--location')
write_out_arg = "%{url_effective}\n%{http_code}"
expected_http_code = conga_aemdst_curl_follow_redirects_expected_http_code

if conga_aemdst_curl_noproxy:
curl_cmdline_args.append('--noproxy "*"')

for header in conga_aemdst_curl_headers:
curl_cmdline_args.append('--header "{}"'.format(header))

curl_base_command = "curl {}".format(" ".join(curl_cmdline_args))
curl_internal_command = '{} --write-out "{}" --output /dev/null --silent {}'.format(curl_base_command,
write_out_arg,
conga_aemdst_curl_url)
curl_debug_command = "{} {}".format(curl_base_command, conga_aemdst_curl_url)

results = {
"curl_base_command": curl_base_command,
"curl_internal_command": curl_internal_command,
"curl_debug_command": curl_debug_command,
"expected_http_code": expected_http_code,
}

result["ansible_facts"] = {
"conga_aemdst_curl_cmdline": results,
}

return result

@staticmethod
def _fail_result(result, message):
result['failed'] = True
result['msg'] = message
return result

def _get_arg_or_var(self, name, default=None, is_required=True):
ret = self._task.args.get(name, self._task_vars.get(name, default))
ret = self._templar.template(ret)
if is_required and ret is None:
raise AnsibleOptionsError("parameter %s is required" % name)
else:
return ret
8 changes: 4 additions & 4 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ conga_aemdst_curl_host: "{{ inventory_hostname }}"
# Allows to overwrite/control the host resolve mechanism of curl
conga_aemdst_curl_resolve:
- host: "{{ conga_aemdst_curl_url | urlsplit('hostname') }}"
port: "80"
address: "127.0.0.1"
port: "{{ conga_aemdst_curl_server_port }}"
address: "{{ conga_aemdst_curl_resolve_ip }}"
- host: "{{ conga_aemdst_curl_url | urlsplit('hostname') }}"
port: "443"
address: "127.0.0.1"
port: "{{ conga_aemdst_curl_server_port_ssl }}"
address: "{{ conga_aemdst_curl_resolve_ip_ssl }}"
85 changes: 14 additions & 71 deletions tasks/curl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,84 +8,27 @@
msg: "Please define the url in variable: 'conga_aemdst_curl_expected_url'"
when: conga_aemdst_curl_expected_url is none

- name: "Set default facts"
set_fact:
_write_out_arg: "%{redirect_url}\n%{http_code}"
_location_arg: ""
_insecure_arg: ""
_noproxy_arg: ""
_resolve_arg: ""
_headers_arg: ""
_expected_http_code: "{{ conga_aemdst_curl_expected_http_code }}"

- name: "Set follow redirect facts"
set_fact:
_write_out_arg: "%{url_effective}\n%{http_code}"
_location_arg: "--location"
_expected_http_code: "{{ conga_aemdst_curl_follow_redirects_expected_http_code }}"
when: conga_aemdst_curl_follow_redirects

- name: "Add '--insecure'"
set_fact:
_insecure_arg: "--insecure"
when: conga_aemdst_curl_allow_insecure

- name: "Add '--noproxy'"
set_fact:
_noproxy_arg: '--noproxy "*"'
when: conga_aemdst_curl_noproxy

- name: "Add '--resolve'."
set_fact:
_resolve_arg: "{{ _resolve_arg }} --resolve '{{ item.host }}:{{ item.port }}:{{ item.address }}'"
with_items:
- "{{ conga_aemdst_curl_resolve }}"
when: conga_aemdst_curl_resolve is defined

- name: "Add '--headers'."
set_fact:
_headers_arg: "{{ _headers_arg }} --header \"{{ item }}\""
with_items:
- "{{ conga_aemdst_curl_headers }}"
when: conga_aemdst_curl_headers is defined

- name: "Set base curl command."
set_fact:
_curl_base_command: >-
curl
{{ _insecure_arg }}
{{ _location_arg }}
{{ _noproxy_arg }}
{{ _resolve_arg }}
{{ _headers_arg }}
--max-time {{ conga_aemdst_curl_timeout }}
--connect-timeout {{ conga_aemdst_curl_connect_timeout }}
- name: "Build curl command line."
curl_cmdline_helper:
tags:
- skip_ansible_lint

- name: "{{ item }} : Set curl commands."
set_fact:
# command used internally only
_curl_internal_command: >-
{{ _curl_base_command }}
--write-out "{{ _write_out_arg }}"
--output /dev/null --silent
{{ conga_aemdst_curl_url }}
# command will be displayed to the user to ensure fast debugging
_curl_debug_command: >-
{{ _curl_base_command }}
{{ conga_aemdst_curl_url }}
- debug:
var: conga_aemdst_curl_cmdline
verbosity: 1

- debug:
msg:
- "check redirect from: {{ conga_aemdst_curl_url }}"
- "check redirect to : {{ conga_aemdst_curl_expected_url }}"
- "check for http code: {{ _expected_http_code }}"
- "check for http code: {{ conga_aemdst_curl_cmdline.expected_http_code }}"
- "Internal curl command:"
- "{{ _curl_internal_command }}"
- "{{ conga_aemdst_curl_cmdline.curl_internal_command }}"
- "Debug curl command:"
- "{{ _curl_debug_command }}"
- "{{ conga_aemdst_curl_cmdline.curl_debug_command }}"

- name: "Executing curl"
shell: "{{ _curl_internal_command }}"
shell: "{{ conga_aemdst_curl_cmdline.curl_internal_command }}"
register: curl_result
delegate_to: "{{ conga_aemdst_curl_host }}"
args:
Expand Down Expand Up @@ -121,11 +64,11 @@
actual : {{ _actual_url }}
when: not conga_aemdst_curl_expected_url_test_lazy

- name: "Assert that actual response code matches {{ _expected_http_code }}"
- name: "Assert that actual response code matches {{ conga_aemdst_curl_cmdline.expected_http_code }}"
assert:
that:
- "{{ _expected_http_code }} == {{ _actual_http_code }}"
- "{{ conga_aemdst_curl_cmdline.expected_http_code }} == {{ _actual_http_code }}"
msg: >-
The actual http_code does not match with expected http_code
expected: {{ _expected_http_code }}
expected: {{ conga_aemdst_curl_cmdline.expected_http_code }}
actual : {{ _actual_http_code }}
19 changes: 0 additions & 19 deletions tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
- name: "Set default port facts"
set_fact:
_initial_port_suffix: ""
_expected_port_suffix: ""

- name: "Set custom initial port suffix"
set_fact:
_initial_port_suffix: ":{{ conga_config.httpd.serverPort }}"
_expected_port_suffix: ":{{ conga_config.httpd.serverPort }}"
when:
- conga_config.httpd.serverPort != 80

- name: "Set custom expected port suffix (http)"
set_fact:
_expected_port_suffix: ":{{ conga_config.httpd.serverPortSsl }}"
when:
- conga_config.httpd.serverPortSsl != 443
- conga_config.httpd.ssl.enforce

- name: "Run aem-publish tests"
include_tasks: aem-publish-tests.yml
when: "'aem-publish' in conga_variants"
Expand Down
Loading

0 comments on commit 5c38cd3

Please sign in to comment.