Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

haproxy addons #62

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,5 @@ venv.bak/

# ansible-galaxy package
*.tar.gz

.DS_Store
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ authors:
- Frederic Bor
- taylor vories
- Jan Wenzel

- Chris Morton

### OPTIONAL but strongly recommended

Expand Down
1 change: 1 addition & 0 deletions plugins/module_utils/__impl/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,4 @@ def parse_interface(self, interface, fail=True, with_virtual=True):
if fail:
self.module.fail_json(msg='%s is not a valid interface' % (interface))
return None

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop the blank line, though I suspect the sanity test will flag this as well.

163 changes: 163 additions & 0 deletions plugins/module_utils/haproxy_frontend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-

# Copyright: (c) 2021, Chris Morton, cosmo@cosmo.2y.net
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type
import re
from ansible_collections.pfsensible.core.plugins.module_utils.module_base import PFSenseModuleBase

HAPROXY_FRONTEND_ARGUMENT_SPEC = dict(
state=dict(default='present', choices=['present', 'absent']),
name=dict(required=True, type='str'),
status=dict(required=True, type='str'),
desc=dict(required=True, type='str'),
type=dict(default='http', choices=['http', 'https']),
httpclose=dict(default='http-keep-alive', choices=['http-keep-alive']),
backend_serverpool=dict(required=False, type='str'),
ssloffloadcert=dict(required=False, type='str'),
ssloffloadcert_type_search=dict(default='descr', type='str'),
ssloffloadacl_an=dict(required=False, type='str'),
max_connections=dict(default=100, type='int'),
addhttp_https_redirect=dict(required=False, type='bool')
)


class PFSenseHaproxyFrontendModule(PFSenseModuleBase):
""" module managing pfsense haproxy frontends """

@staticmethod
def get_argument_spec():
""" return argument spec """
return HAPROXY_FRONTEND_ARGUMENT_SPEC

##############################
# init
#
def __init__(self, module, pfsense=None):
super(PFSenseHaproxyFrontendModule, self).__init__(module, pfsense)
self.name = "pfsense_haproxy_frontend"
self.obj = dict()

pkgs_elt = self.pfsense.get_element('installedpackages')
self.haproxy = pkgs_elt.find('haproxy') if pkgs_elt is not None else None
self.root_elt = self.haproxy.find('ha_backends') if self.haproxy is not None else None
if self.root_elt is None:
self.module.fail_json(msg='Unable to find frontends (ha_backends) XML configuration entry. Are you sure haproxy is installed ?')

self.servers = None

##############################
# params processing
#
def _params_to_obj(self):
""" return a frontend dict from module params """
params = self.params

obj = dict()
obj['name'] = self.params['name']
if self.params['state'] == 'present':
self._get_ansible_param(obj, 'desc')
self._get_ansible_param(obj, 'type')
self._get_ansible_param(obj, 'status')
self._get_ansible_param(obj, 'httpclose')
self._get_ansible_param(obj, 'backend_serverpool')
self._get_ansible_param(obj, 'max_connections')

if 'ssloffloadcert' in params and params['ssloffloadcert'] is not None and params['ssloffloadcert'] != '':
search_field_type='type'
if 'ssloffloadcert_type_search' in params and params['ssloffloadcert_type_search'] is not None and params['ssloffloadcert_type_search'] != '':
search_field_type = params['ssloffloadcert_type_search']

cert_elt = self.pfsense.find_cert_elt(params['ssloffloadcert'], search_field=search_field_type)
if cert_elt is None:
self.module.fail_json(msg='%s is not a valid certificate ' % (params['ssloffloadcert']))
obj['ssloffloadcert'] = cert_elt.find('refid').text

self._get_ansible_param(obj, 'ssloffloadacl_an')

#check for redirect
if 'addhttp_https_redirect' in params and params['addhttp_https_redirect'] is not None and params['addhttp_https_redirect'] != '' and params['addhttp_https_redirect']:
#add redirect rules
aval = dict()
val = dict()
val['action'] = 'http-request_redirect'
val['http-request_redirectrule'] = 'scheme https'
aval['item'] = val
obj['a_actionitems'] = aval


return obj

def _validate_params(self):
""" do some extra checks on input parameters """
# check name
if re.search(r'[^a-zA-Z0-9\.\-_]', self.params['name']) is not None:
self.module.fail_json(msg="The field 'name' contains invalid characters.")

##############################
# XML processing
#
def _create_target(self):
""" create the XML target_elt """
server_elt = self.pfsense.new_element('item')
return server_elt

def _find_target(self):
""" find the XML target_elt """
for item_elt in self.root_elt:
if item_elt.tag != 'item':
continue
name_elt = item_elt.find('name')
if name_elt is not None and name_elt.text == self.obj['name']:
return item_elt
return None

def _get_next_id(self):
""" get next free haproxy id """
max_id = 99
id_elts = self.haproxy.findall('.//id')
for id_elt in id_elts:
if id_elt.text is None:
continue
ha_id = int(id_elt.text)
if ha_id > max_id:
max_id = ha_id
return str(max_id + 1)

##############################
# run
#
def _update(self):
""" make the target pfsense reload haproxy """
return self.pfsense.phpshell('''require_once("haproxy/haproxy.inc");
$result = haproxy_check_and_run($savemsg, true); if ($result) unlink_if_exists($d_haproxyconfdirty_path);''')

##############################
# Logging
#
def _log_fields(self, before=None):
""" generate pseudo-CLI command fields parameters to create an obj """
values = ''
if before is None:
values += self.format_cli_field(self.params, 'desc')
values += self.format_cli_field(self.params, 'type')
values += self.format_cli_field(self.params, 'httpclose')
values += self.format_cli_field(self.params, 'backend_serverpool')
values += self.format_cli_field(self.params, 'ssloffloadcert')
values += self.format_cli_field(self.params, 'ssloffloadacl_an')
values += self.format_cli_field(self.params, 'max_connections')
else:
values += self.format_updated_cli_field(self.obj, before, 'desc', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'type', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'httpclose', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'backend_serverpool', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'ssloffloadcert', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'ssloffloadacl_an', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'max_connections', add_comma=(values))
return values

def _get_obj_name(self):
""" return obj's name """
return "'{0}'".format(self.obj['name'])
139 changes: 139 additions & 0 deletions plugins/module_utils/haproxy_frontend_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-

# Copyright: (c) 2021, Chris Morton, cosmo@cosmo.2y.net
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type
import re
from ansible_collections.pfsensible.core.plugins.module_utils.module_base import PFSenseModuleBase

HAPROXY_FRONTEND_SERVER_ARGUMENT_SPEC = dict(
state=dict(default='present', choices=['present', 'absent']),
frontend=dict(required=True, type='str'),
extaddr=dict(required=True, type='str'),
extaddr_port=dict(required=True, type='int'),
extaddr_ssl=dict(required=True, type='str'),
)


class PFSenseHaproxyFrontendServerModule(PFSenseModuleBase):
""" module managing pfsense haproxy frontends """

@staticmethod
def get_argument_spec():
""" return argument spec """
return HAPROXY_FRONTEND_SERVER_ARGUMENT_SPEC

##############################
# init
#
def __init__(self, module, pfsense=None):
super(PFSenseHaproxyFrontendServerModule, self).__init__(module, pfsense)
self.name = "pfsense_haproxy_frontend_server"
self.root_elt = None
self.obj = dict()

pkgs_elt = self.pfsense.get_element('installedpackages')
self.haproxy = pkgs_elt.find('haproxy') if pkgs_elt is not None else None
self.frontends = self.haproxy.find('ha_backends') if self.haproxy is not None else None
if self.frontends is None:
self.module.fail_json(msg='Unable to find frontends (ha_backends) XML configuration entry. Are you sure haproxy is installed ?')

self.frontend = None

##############################
# params processing
#
def _params_to_obj(self):
""" return a frontend dict from module params """
obj = dict()
self._get_ansible_param(obj, 'extaddr')
self._get_ansible_param(obj, 'extaddr_port')
self._get_ansible_param(obj, 'extaddr_ssl')
obj['name'] = "'{0}_{1}'".format(self.params['extaddr'],self.params['extaddr_port'])

return obj

def _validate_params(self):
""" do some extra checks on input parameters """

#get the frontend
self.frontend = self._find_frontend(self.params['frontend'])
if self.frontend is None:
self.module.fail_json(msg="The frontend named '{0}' does not exist".format(self.params['frontend']))

#setup the a_extaddr if we dont hav eit
self.root_elt = self.frontend.find('a_extaddr')
if self.root_elt is None:
self.root_elt = self.pfsense.new_element('a_extaddr')
self.frontend.append(self.root_elt)

##############################
# XML processing
#
def _create_target(self):
""" create the XML target_elt """
server_elt = self.pfsense.new_element('item')
return server_elt

def _find_frontend(self, name):
""" return the target frontend_elt if found """
for item_elt in self.frontends:
if item_elt.tag != 'item':
continue
name_elt = item_elt.find('name')
if name_elt is not None and name_elt.text == name:
return item_elt
return None

def _find_target(self):
""" find the XML target_elt """
for item_elt in self.root_elt:
if item_elt.tag != 'item':
continue
name_elt = item_elt.find('name')
print(name_elt)
if name_elt is not None and name_elt.text == self.obj['name']:
return item_elt
return None

def _get_next_id(self):
""" get next free haproxy id """
max_id = 99
id_elts = self.haproxy.findall('.//id')
for id_elt in id_elts:
if id_elt.text is None:
continue
ha_id = int(id_elt.text)
if ha_id > max_id:
max_id = ha_id
return str(max_id + 1)

##############################
# run
#
def _update(self):
""" make the target pfsense reload haproxy """
return self.pfsense.phpshell('''require_once("haproxy/haproxy.inc");
$result = haproxy_check_and_run($savemsg, true); if ($result) unlink_if_exists($d_haproxyconfdirty_path);''')

##############################
# Logging
#
def _log_fields(self, before=None):
""" generate pseudo-CLI command fields parameters to create an obj """
values = ''
if before is None:
values += self.format_cli_field(self.params, 'extaddr')
values += self.format_cli_field(self.params, 'extaddr_port')
values += self.format_cli_field(self.params, 'extaddr_ssl')
else:
values += self.format_updated_cli_field(self.obj, before, 'extaddr', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'extaddr_port', add_comma=(values))
values += self.format_updated_cli_field(self.obj, before, 'extaddr_ssl', add_comma=(values))
return values

def _get_obj_name(self):
""" return obj's name """
return "'{0}_{1}'".format(self.obj['extaddr'],self.obj['extaddr_port'])
2 changes: 2 additions & 0 deletions plugins/module_utils/pfsense.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,8 @@ def find_schedule_elt(self, name):
""" return schedule elt if found """
return self.find_elt_xpath("./schedules/schedule[name='{0}']".format(name))



Comment on lines +632 to +633
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a mistake

@staticmethod
def uniqid(prefix='', more_entropy=False):
""" return an identifier based on time """
Expand Down
Loading
Loading