diff options
Diffstat (limited to 'web_infrastructure')
-rw-r--r-- | web_infrastructure/apache2_module.py | 15 | ||||
-rw-r--r-- | web_infrastructure/django_manage.py | 8 | ||||
-rw-r--r-- | web_infrastructure/htpasswd.py | 56 | ||||
-rw-r--r-- | web_infrastructure/supervisorctl.py | 25 |
4 files changed, 84 insertions, 20 deletions
diff --git a/web_infrastructure/apache2_module.py b/web_infrastructure/apache2_module.py index 39351482..cb43ba9b 100644 --- a/web_infrastructure/apache2_module.py +++ b/web_infrastructure/apache2_module.py @@ -20,6 +20,7 @@ DOCUMENTATION = ''' --- module: apache2_module version_added: 1.6 +author: "Christian Berendt (@berendt)" short_description: enables/disables a module of the Apache2 webserver description: - Enables or disables a specified module of the Apache2 webserver. @@ -34,6 +35,7 @@ options: choices: ['present', 'absent'] default: present +requirements: ["a2enmod","a2dismod"] ''' EXAMPLES = ''' @@ -49,9 +51,12 @@ import re def _disable_module(module): name = module.params['name'] a2dismod_binary = module.get_bin_path("a2dismod") + if a2dismod_binary is None: + module.fail_json(msg="a2dismod not found. Perhaps this system does not use a2dismod to manage apache") + result, stdout, stderr = module.run_command("%s %s" % (a2dismod_binary, name)) - if re.match(r'.*' + name + r' already disabled.*', stdout, re.S): + if re.match(r'.*\b' + name + r' already disabled', stdout, re.S): module.exit_json(changed = False, result = "Success") elif result != 0: module.fail_json(msg="Failed to disable module %s: %s" % (name, stdout)) @@ -61,9 +66,12 @@ def _disable_module(module): def _enable_module(module): name = module.params['name'] a2enmod_binary = module.get_bin_path("a2enmod") + if a2enmod_binary is None: + module.fail_json(msg="a2enmod not found. Perhaps this system does not use a2enmod to manage apache") + result, stdout, stderr = module.run_command("%s %s" % (a2enmod_binary, name)) - if re.match(r'.*' + name + r' already enabled.*', stdout, re.S): + if re.match(r'.*\b' + name + r' already enabled', stdout, re.S): module.exit_json(changed = False, result = "Success") elif result != 0: module.fail_json(msg="Failed to enable module %s: %s" % (name, stdout)) @@ -86,4 +94,5 @@ def main(): # import module snippets from ansible.module_utils.basic import * -main() +if __name__ == '__main__': + main() diff --git a/web_infrastructure/django_manage.py b/web_infrastructure/django_manage.py index d71001fd..17b0534d 100644 --- a/web_infrastructure/django_manage.py +++ b/web_infrastructure/django_manage.py @@ -93,7 +93,7 @@ notes: - To be able to use the migrate command, you must have south installed and added as an app in your settings - To be able to use the collectstatic command, you must have enabled staticfiles in your settings requirements: [ "virtualenv", "django" ] -author: Scott Anderson +author: "Scott Anderson (@tastychutney)" ''' EXAMPLES = """ @@ -222,7 +222,7 @@ def main(): ) command = module.params['command'] - app_path = module.params['app_path'] + app_path = os.path.expanduser(module.params['app_path']) virtualenv = module.params['virtualenv'] for param in specific_params: @@ -236,8 +236,6 @@ def main(): if not module.params[param]: module.fail_json(msg='%s param is required for command=%s' % (param, command)) - venv = module.params['virtualenv'] - _ensure_virtualenv(module) cmd = "python manage.py %s" % (command, ) @@ -258,7 +256,7 @@ def main(): if module.params[param]: cmd = '%s %s' % (cmd, module.params[param]) - rc, out, err = module.run_command(cmd, cwd=app_path) + rc, out, err = module.run_command(cmd, cwd=os.path.expanduser(app_path)) if rc != 0: if command == 'createcachetable' and 'table' in err and 'already exists' in err: out = 'Already exists.' diff --git a/web_infrastructure/htpasswd.py b/web_infrastructure/htpasswd.py index 4a72ea37..e567a776 100644 --- a/web_infrastructure/htpasswd.py +++ b/web_infrastructure/htpasswd.py @@ -46,7 +46,10 @@ options: choices: ["apr_md5_crypt", "des_crypt", "ldap_sha1", "plaintext"] default: "apr_md5_crypt" description: - - Encryption scheme to be used. + - Encryption scheme to be used. As well as the four choices listed + here, you can also use any other hash supported by passlib, such as + md5_crypt and sha256_crypt, which are linux passwd hashes. If you + do so the password file will not be compatible with Apache or Nginx state: required: false choices: [ present, absent ] @@ -66,7 +69,7 @@ notes: - "On Debian, Ubuntu, or Fedora: install I(python-passlib)." - "On RHEL or CentOS: Enable EPEL, then install I(python-passlib)." requires: [ passlib>=1.6 ] -author: Lorin Hochstein +author: "Lorin Hochstein (@lorin)" """ EXAMPLES = """ @@ -74,20 +77,25 @@ EXAMPLES = """ - htpasswd: path=/etc/nginx/passwdfile name=janedoe password=9s36?;fyNp owner=root group=www-data mode=0640 # Remove a user from a password file - htpasswd: path=/etc/apache2/passwdfile name=foobar state=absent +# Add a user to a password file suitable for use by libpam-pwdfile +- htpasswd: path=/etc/mail/passwords name=alex password=oedu2eGh crypt_scheme=md5_crypt """ import os +import tempfile from distutils.version import StrictVersion try: - from passlib.apache import HtpasswdFile + from passlib.apache import HtpasswdFile, htpasswd_context + from passlib.context import CryptContext import passlib except ImportError: passlib_installed = False else: passlib_installed = True +apache_hashes = ["apr_md5_crypt", "des_crypt", "ldap_sha1", "plaintext"] def create_missing_directories(dest): destpath = os.path.dirname(dest) @@ -99,6 +107,10 @@ def present(dest, username, password, crypt_scheme, create, check_mode): """ Ensures user is present Returns (msg, changed) """ + if crypt_scheme in apache_hashes: + context = htpasswd_context + else: + context = CryptContext(schemes = [ crypt_scheme ] + apache_hashes) if not os.path.exists(dest): if not create: raise ValueError('Destination %s does not exist' % dest) @@ -106,9 +118,9 @@ def present(dest, username, password, crypt_scheme, create, check_mode): return ("Create %s" % dest, True) create_missing_directories(dest) if StrictVersion(passlib.__version__) >= StrictVersion('1.6'): - ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme) + ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, context=context) else: - ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme) + ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, context=context) if getattr(ht, 'set_password', None): ht.set_password(username, password) else: @@ -117,9 +129,9 @@ def present(dest, username, password, crypt_scheme, create, check_mode): return ("Created %s and added %s" % (dest, username), True) else: if StrictVersion(passlib.__version__) >= StrictVersion('1.6'): - ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme) + ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, context=context) else: - ht = HtpasswdFile(dest, default=crypt_scheme) + ht = HtpasswdFile(dest, default=crypt_scheme, context=context) found = None if getattr(ht, 'check_password', None): @@ -198,6 +210,36 @@ def main(): if not passlib_installed: module.fail_json(msg="This module requires the passlib Python library") + # Check file for blank lines in effort to avoid "need more than 1 value to unpack" error. + try: + f = open(path, "r") + except IOError: + # No preexisting file to remove blank lines from + f = None + else: + try: + lines = f.readlines() + finally: + f.close() + + # If the file gets edited, it returns true, so only edit the file if it has blank lines + strip = False + for line in lines: + if not line.strip(): + strip = True + break + + if strip: + # If check mode, create a temporary file + if check_mode: + temp = tempfile.NamedTemporaryFile() + path = temp.name + f = open(path, "w") + try: + [ f.write(line) for line in lines if line.strip() ] + finally: + f.close() + try: if state == 'present': (msg, changed) = present(path, username, password, crypt_scheme, create, check_mode) diff --git a/web_infrastructure/supervisorctl.py b/web_infrastructure/supervisorctl.py index f75992b9..28f341d8 100644 --- a/web_infrastructure/supervisorctl.py +++ b/web_infrastructure/supervisorctl.py @@ -64,7 +64,7 @@ options: - The desired state of program/group. required: true default: null - choices: [ "present", "started", "stopped", "restarted" ] + choices: [ "present", "started", "stopped", "restarted", "absent" ] supervisorctl_path: description: - path to supervisorctl executable @@ -75,7 +75,9 @@ notes: - When C(state) = I(present), the module will call C(supervisorctl reread) then C(supervisorctl add) if the program/group does not exist. - When C(state) = I(restarted), the module will call C(supervisorctl update) then call C(supervisorctl restart). requirements: [ "supervisorctl" ] -author: Matt Wright, Aaron Wang <inetfuture@gmail.com> +author: + - "Matt Wright (@mattupstate)" + - "Aaron Wang (@inetfuture) <inetfuture@gmail.com>" ''' EXAMPLES = ''' @@ -101,7 +103,7 @@ def main(): username=dict(required=False), password=dict(required=False), supervisorctl_path=dict(required=False), - state=dict(required=True, choices=['present', 'started', 'restarted', 'stopped']) + state=dict(required=True, choices=['present', 'started', 'restarted', 'stopped', 'absent']) ) module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True) @@ -183,19 +185,32 @@ def main(): if module.check_mode: module.exit_json(changed=True) for process_name in to_take_action_on: - rc, out, err = run_supervisorctl(action, process_name) + rc, out, err = run_supervisorctl(action, process_name, check_rc=True) if '%s: %s' % (process_name, expected_result) not in out: module.fail_json(msg=out) module.exit_json(changed=True, name=name, state=state, affected=to_take_action_on) if state == 'restarted': - rc, out, err = run_supervisorctl('update') + rc, out, err = run_supervisorctl('update', check_rc=True) processes = get_matched_processes() take_action_on_processes(processes, lambda s: True, 'restart', 'started') processes = get_matched_processes() + if state == 'absent': + if len(processes) == 0: + module.exit_json(changed=False, name=name, state=state) + + if module.check_mode: + module.exit_json(changed=True) + run_supervisorctl('reread', check_rc=True) + rc, out, err = run_supervisorctl('remove', name) + if '%s: removed process group' % name in out: + module.exit_json(changed=True, name=name, state=state) + else: + module.fail_json(msg=out, name=name, state=state) + if state == 'present': if len(processes) > 0: module.exit_json(changed=False, name=name, state=state) |