├── .gitignore ├── meta └── runtime.yml ├── roles ├── ssl │ ├── defaults │ │ └── main.yml │ ├── templates │ │ └── extfile.cnf.j2 │ ├── tasks │ │ ├── ca.yml │ │ ├── cert.yml │ │ ├── gen-ca.yml │ │ ├── main.yml │ │ ├── distribute.yml │ │ └── gen-cert.yml │ └── README.md ├── supervisor │ ├── templates │ │ ├── centos.init.j2 │ │ ├── systemd.init.j2 │ │ ├── supervisord.conf.j2 │ │ ├── redhat.init.j2 │ │ ├── debian.init.j2 │ │ └── ubuntu.init.j2 │ ├── handlers │ │ └── main.yml │ ├── vars │ │ ├── redhat_package.yml │ │ ├── debian_package.yml │ │ └── virtualenv.yml │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ ├── package.yml │ │ ├── main.yml │ │ ├── virtualenv-unprivileged.yml │ │ └── virtualenv.yml │ └── README.md ├── ceph_mount │ ├── defaults │ │ └── main.yml │ ├── README.md │ └── tasks │ │ └── main.yml ├── ssh │ ├── vars │ │ ├── default.yml │ │ ├── _smartos_zone.yml │ │ └── redhat.yml │ ├── handlers │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ └── smartos_zone_openssh.yml │ └── README.md ├── virtual │ ├── handlers │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ ├── files │ │ ├── zfs-mount.service │ │ └── ebs-nvme-mapping.sh │ ├── tasks │ │ ├── amazon-ec2.yml │ │ ├── main.yml │ │ └── lx-brand.yml │ └── README.md ├── remote_management │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── cron │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── firewall │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── paths │ ├── library │ │ ├── README │ │ └── zfs_delegate_admin.py │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ ├── install_zfs_redhat.yml │ │ └── main.yml │ └── README.md ├── resolv │ ├── tasks │ │ ├── main.yml │ │ └── linux.yml │ ├── templates │ │ └── resolv.conf.j2 │ └── README.md ├── timezone │ ├── handlers │ │ └── main.yml │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── copy │ ├── defaults │ │ └── main.yml │ ├── templates │ │ └── ini.j2 │ ├── README.md │ └── tasks │ │ └── main.yml ├── locale │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── services │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── README.md ├── users │ ├── tasks │ │ ├── main.yml │ │ ├── non-solaris.yml │ │ ├── solaris.yml │ │ └── ssh.yml │ └── README.md ├── openstack │ ├── defaults │ │ └── main.yml │ ├── tasks │ │ ├── clean.yml │ │ ├── secrets.yml │ │ ├── main.yml │ │ ├── initialize.yml │ │ └── spawn.yml │ └── README.md ├── requiretty │ ├── tasks │ │ └── main.yml │ └── README.md ├── login_defs │ ├── tasks │ │ └── main.yml │ └── README.md ├── kernel_params │ ├── tasks │ │ └── main.yml │ └── README.md ├── systemd │ ├── templates │ │ ├── overrides.conf.j2 │ │ └── resource_controls.conf.j2 │ ├── handlers │ │ └── main.yml │ ├── README.md │ └── tasks │ │ └── main.yml ├── packages │ ├── defaults │ │ └── main.yml │ ├── README.md │ └── tasks │ │ └── main.yml └── required_vars │ ├── README.md │ └── tasks │ └── main.yml ├── plugins ├── filter │ ├── toml.py │ └── inheritance_utils.py └── lookup │ └── inheritance_chain.py ├── README.md ├── LICENSE └── galaxy.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.*.swp 3 | *.pyc 4 | -------------------------------------------------------------------------------- /meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | requires_ansible: '>=2.11.0' 3 | -------------------------------------------------------------------------------- /roles/ssl/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssl_cas: {} 4 | -------------------------------------------------------------------------------- /roles/supervisor/templates/centos.init.j2: -------------------------------------------------------------------------------- 1 | redhat.init.j2 -------------------------------------------------------------------------------- /roles/ceph_mount/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ceph_mount_state: mounted 4 | -------------------------------------------------------------------------------- /roles/ssh/vars/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_config_dir: /etc/ssh 4 | ssh_service_name: ssh 5 | -------------------------------------------------------------------------------- /roles/virtual/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: trigger udevd 4 | command: udevadm trigger 5 | -------------------------------------------------------------------------------- /roles/ssh/vars/_smartos_zone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_config_dir: /opt/local/etc/ssh 4 | ssh_service_name: openssh 5 | -------------------------------------------------------------------------------- /roles/remote_management/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: debian update-grub 4 | command: /usr/sbin/update-grub 5 | -------------------------------------------------------------------------------- /roles/ssh/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reload sshd 4 | service: name={{ ssh_service_name }} state=reloaded 5 | -------------------------------------------------------------------------------- /roles/ssl/templates/extfile.cnf.j2: -------------------------------------------------------------------------------- 1 | {% for k, v in ssl_cert_def.ext.items() %} 2 | {{ k }} = {{ v }} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /roles/cron/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all_crontabs: [] 4 | group_crontabs: [] 5 | host_crontabs: [] 6 | crontabs: [] 7 | -------------------------------------------------------------------------------- /roles/ssh/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ssh_all_sshd_config: [] 4 | ssh_group_sshd_config: [] 5 | ssh_host_sshd_config: [] 6 | -------------------------------------------------------------------------------- /roles/firewall/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all_firewall_rules: [] 4 | group_firewall_rules: [] 5 | host_firewall_rules: [] 6 | -------------------------------------------------------------------------------- /roles/paths/library/README: -------------------------------------------------------------------------------- 1 | zfs_delegate_admin awaiting review/merge: 2 | 3 | https://github.com/ansible/ansible/pull/19240/files 4 | -------------------------------------------------------------------------------- /roles/ssh/vars/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # CentOS 7 anyway. Not sure about 6. 4 | ssh_config_dir: /etc/ssh 5 | ssh_service_name: sshd 6 | -------------------------------------------------------------------------------- /roles/resolv/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include_tasks: linux.yml 4 | when: ansible_system == "Linux" and resolv_nameservers is defined 5 | -------------------------------------------------------------------------------- /roles/timezone/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: persist timezone on debian 4 | command: dpkg-reconfigure --frontend noninteractive tzdata 5 | -------------------------------------------------------------------------------- /roles/copy/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all_files: [] 4 | group_files: [] 5 | host_files: [] 6 | all_templates: [] 7 | group_templates: [] 8 | host_templates: [] 9 | -------------------------------------------------------------------------------- /roles/cron/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: refresh cron 4 | service: 5 | name: cron 6 | state: reloaded 7 | when: ansible_os_family == 'Solaris' 8 | -------------------------------------------------------------------------------- /roles/resolv/templates/resolv.conf.j2: -------------------------------------------------------------------------------- 1 | {% for ns in resolv_nameservers %} 2 | nameserver {{ ns }} 3 | {% endfor %} 4 | domain {{ resolv_domain }} 5 | search {{ resolv_search }} 6 | -------------------------------------------------------------------------------- /roles/virtual/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | virtual_lx_disable_services_redhat: 4 | "8": 5 | - rsyslog.service 6 | "9": 7 | - dbus-broker.service 8 | - rsyslog.service 9 | -------------------------------------------------------------------------------- /roles/locale/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reconfigure locales 4 | command: dpkg-reconfigure -f noninteractive locales 5 | environment: 6 | DEBIAN_FRONTEND: noninteractive 7 | -------------------------------------------------------------------------------- /roles/services/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all_service_configurations: [] 4 | group_service_configurations: [] 5 | host_service_configurations: [] 6 | all_services: [] 7 | group_services: [] 8 | host_services: [] 9 | -------------------------------------------------------------------------------- /roles/users/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - import_tasks: solaris.yml 4 | when: ansible_os_family == 'Solaris' 5 | 6 | - import_tasks: non-solaris.yml 7 | when: ansible_os_family != 'Solaris' 8 | 9 | - import_tasks: ssh.yml 10 | -------------------------------------------------------------------------------- /roles/openstack/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | openstack_manage_secrets: true 4 | 5 | # timeout value for spawn openstack.cloud.server task 6 | #openstack_spawn_timeout: omit 7 | 8 | # timeout value for spawn ansible.builtin.wait_for_connection task 9 | openstack_wait_timeout: 120 10 | -------------------------------------------------------------------------------- /roles/supervisor/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # file: roles/supervisor/handlers/main.yml 3 | 4 | - name: update supervisord 5 | command: "{{ supervisord_prefix }}/bin/supervisorctl update" 6 | 7 | - name: restart supervisord 8 | command: "{{ supervisord_prefix }}/bin/supervisorctl reload" 9 | -------------------------------------------------------------------------------- /roles/timezone/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # IIRC there were packages on Debian that required a timezone to be set, but I don't recall which ones. Anyway, this 4 | # should default to UTC if we always set a timezone when the role is executed as it previously did. 5 | #timezone: America/New_York 6 | -------------------------------------------------------------------------------- /roles/copy/templates/ini.j2: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 3 | ;; 4 | 5 | {% set ini = item.contents %} 6 | {% for section in ini %} 7 | [{{ section }}] 8 | {% for opt in ini[section] %} 9 | {{ opt }} = {{ ini[section][opt] }} 10 | {% endfor %} 11 | {% endfor %} 12 | -------------------------------------------------------------------------------- /plugins/filter/toml.py: -------------------------------------------------------------------------------- 1 | import toml 2 | import json 3 | 4 | 5 | def to_toml(v): 6 | s = json.dumps(dict(v)) 7 | d = json.loads(s) 8 | return toml.dumps(d) 9 | 10 | 11 | class FilterModule(object): 12 | def filters(self): 13 | return { 14 | 'to_toml': to_toml, 15 | } 16 | -------------------------------------------------------------------------------- /roles/supervisor/vars/redhat_package.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | supervisord_prefix: /usr 4 | supervisord_conf_path: /etc/supervisord.conf 5 | supervisord_conf_dir: /etc/supervisord.d 6 | supervisord_sock_path: /var/run/supervisor/supervisor.sock 7 | supervisord_log_dir: /var/log/supervisor 8 | supervisord_conf_ext: ini 9 | supervisord_service_name: supervisord 10 | -------------------------------------------------------------------------------- /roles/supervisor/vars/debian_package.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | supervisord_prefix: /usr 4 | supervisord_conf_path: /etc/supervisor/supervisord.conf 5 | supervisord_conf_dir: /etc/supervisor/conf.d 6 | supervisord_sock_path: /var/run/supervisor.sock 7 | supervisord_log_dir: /var/log/supervisor 8 | supervisord_conf_ext: conf 9 | supervisord_service_name: supervisor 10 | -------------------------------------------------------------------------------- /roles/requiretty/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Detect /etc/sudoers 4 | stat: path=/etc/sudoers 5 | register: etc_sudoers 6 | 7 | - name: Disable sudo requiretty for Ansible pipelining 8 | lineinfile: dest=/etc/sudoers regexp="^Defaults(\s+)(.*)requiretty(.*)" line="#Defaults\1\2requiretty\3" backrefs=yes 9 | when: etc_sudoers.stat.exists 10 | 11 | -------------------------------------------------------------------------------- /roles/virtual/files/zfs-mount.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Mount Native ZFS filesystems 3 | Documentation=man:zfs(8) 4 | DefaultDependencies=no 5 | Conflicts=shutdown.target 6 | After=local-fs.target 7 | Before=sysinit.target shutdown.target 8 | 9 | [Service] 10 | Type=oneshot 11 | ExecStart=/native/usr/sbin/zfs mount -a 12 | 13 | [Install] 14 | WantedBy=basic.target 15 | -------------------------------------------------------------------------------- /roles/remote_management/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Tasks related to remote management 3 | 4 | - name: Set serial console 5 | lineinfile: 6 | dest: /etc/default/grub 7 | line: GRUB_CMDLINE_LINUX="console={{ linux_console }}" 8 | regexp: "^GRUB_CMDLINE_LINUX=.*$" 9 | backup: yes 10 | notify: 11 | - debian update-grub 12 | when: linux_console is defined and ansible_os_family == "Debian" 13 | -------------------------------------------------------------------------------- /roles/login_defs/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Modify /etc/login.defs 4 | ansible.builtin.lineinfile: 5 | dest: /etc/login.defs 6 | regexp: '^#?\s*{{ item.key }}\s+.*' 7 | line: "{{ item.key }} {{ item.value }}" 8 | owner: root 9 | group: root 10 | mode: "0644" 11 | loop: "{{ login_defs | ansible.builtin.dict2items }}" 12 | when: login_defs is defined and ansible_system == "Linux" 13 | -------------------------------------------------------------------------------- /roles/ssl/tasks/ca.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: CA cert tasks 4 | block: 5 | 6 | - name: Check CA cert existence 7 | stat: 8 | path: "{{ ssl_dir }}/ca.pem" 9 | register: ssl_ca_cert_stat_out 10 | 11 | - name: Include CA generation tasks 12 | include_tasks: gen-ca.yml 13 | when: not ssl_ca_cert_stat_out.stat.exists 14 | 15 | delegate_to: localhost 16 | become: false 17 | run_once: true 18 | -------------------------------------------------------------------------------- /roles/virtual/files/ebs-nvme-mapping.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # https://github.com/oogali/ebs-automatic-nvme-mapping/pull/3 3 | 4 | if [[ -x /usr/sbin/nvme ]] && [[ -b ${1} ]]; then 5 | nvme_link=$( \ 6 | /usr/sbin/nvme id-ctrl --raw-binary "${1}" | \ 7 | /usr/bin/cut -c3073-3104 | \ 8 | /bin/sed 's/^\/dev\///g'| \ 9 | /bin/sed 's/^sd/xvd/'| \ 10 | /usr/bin/tr -d '[:space:]' \ 11 | ); 12 | echo $nvme_link; 13 | fi 14 | -------------------------------------------------------------------------------- /roles/kernel_params/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Set kernel parameters 4 | sysctl: 5 | name: "{{ item.name }}" 6 | value: "{{ item.value }}" 7 | state: "{{ item.state | default(omit) }}" 8 | reload: "{{ item.reload | default(omit) }}" 9 | sysctl_file: /etc/sysctl.d/98-ansible.conf 10 | sysctl_set: "{{ item.sysctl_set | default(omit) }}" 11 | with_galaxyproject.general.inheritance_chain: "kernel_params" 12 | -------------------------------------------------------------------------------- /roles/supervisor/vars/virtualenv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | supervisord_prefix: /opt/supervisor 4 | supervisord_conf_path: /etc/supervisord.conf 5 | supervisord_conf_dir: /etc/opt/supervisor 6 | supervisord_sock_path: /var/run/supervisor.sock 7 | supervisord_log_dir: /var/log/supervisord 8 | supervisord_run_dir: /var/run 9 | supervisord_conf_ext: conf 10 | supervisord_service_name: supervisor 11 | 12 | #supervisord_inet_listen: 127.0.0.1 13 | #supervisord_inet_port: 9001 14 | -------------------------------------------------------------------------------- /roles/systemd/templates/overrides.conf.j2: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This file is managed by Ansible. ALL CHANGES WILL BE OVERWRITTEN. 3 | ;; 4 | [{{ item.unit_type | default("service") | title }}] 5 | {% if item.override is not string and item.override is not mapping and item.override is iterable %} 6 | {% for item in item.override %} 7 | {{ item }} 8 | {% endfor %} 9 | {% else %} 10 | {% for key in item.override %} 11 | {{ key }}={{ item.override[key] }} 12 | {% endfor %} 13 | {% endif %} 14 | -------------------------------------------------------------------------------- /roles/supervisor/templates/systemd.init.j2: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 3 | ;; 4 | 5 | [Unit] 6 | Description=Run a set of applications as daemons 7 | After=local-fs.target remote-fs.target network.target 8 | 9 | [Service] 10 | ExecStart={{ supervisord_prefix }}/bin/supervisord -c {{ supervisord_conf_path }} -n 11 | ExecReload=/bin/kill -HUP $MAINPID 12 | KillMode=process 13 | Restart=on-failure 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /roles/openstack/tasks/clean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Remove clouds.yaml 4 | ansible.builtin.file: 5 | path: "{{ playbook_dir }}/clouds.yaml" 6 | state: absent 7 | delegate_to: localhost 8 | run_once: true 9 | become: false 10 | 11 | - name: Remove additional secrets 12 | ansible.builtin.file: 13 | path: "{{ playbook_dir }}/{{ item.dest }}" 14 | state: absent 15 | loop: "{{ os_secrets | default([]) }}" 16 | delegate_to: localhost 17 | run_once: yes 18 | no_log: yes 19 | -------------------------------------------------------------------------------- /roles/paths/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | zfs_on_linux_release_version: "2.8" 4 | 5 | # options: kabi, dkms 6 | zfs_on_linux_kmod_style: kabi 7 | 8 | zfs_on_linux_package_name: zfs 9 | 10 | zfs_on_linux_repo_states: "{{ __zfs_on_linux_repo_states[zfs_on_linux_kmod_style] }}" 11 | __zfs_on_linux_repo_states: 12 | kabi: 13 | - name: zfs 14 | state: disabled 15 | - name: zfs-kmod 16 | state: enabled 17 | dkms: 18 | - name: zfs 19 | state: enabled 20 | - name: zfs-kmod 21 | state: disabled 22 | -------------------------------------------------------------------------------- /roles/openstack/tasks/secrets.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Write clouds.yaml 4 | ansible.builtin.copy: 5 | content: "{{ os_clouds_yaml | to_nice_yaml }}" 6 | dest: "{{ playbook_dir }}/clouds.yaml" 7 | mode: "0400" 8 | delegate_to: localhost 9 | run_once: true 10 | no_log: yes 11 | 12 | - name: Write additional secrets 13 | ansible.builtin.copy: 14 | content: "{{ item.content }}" 15 | dest: "{{ playbook_dir }}/{{ item.dest }}" 16 | mode: "0400" 17 | loop: "{{ os_secrets | default([]) }}" 18 | delegate_to: localhost 19 | run_once: yes 20 | loop_control: 21 | label: "{{ item.dest }}" 22 | -------------------------------------------------------------------------------- /roles/ssl/tasks/cert.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Cert tasks 4 | block: 5 | 6 | - name: Check cert existence 7 | stat: 8 | path: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}.pem" 9 | run_once: "{{ false if cert_item.per_host is defined and cert_item.per_host else true }}" 10 | register: ssl_cert_stat_out 11 | 12 | - name: Include cert generation tasks 13 | include_tasks: gen-cert.yml 14 | run_once: "{{ false if cert_item.per_host is defined and cert_item.per_host else true }}" 15 | when: not ssl_cert_stat_out.stat.exists 16 | 17 | delegate_to: localhost 18 | become: false 19 | -------------------------------------------------------------------------------- /roles/ssh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Set ssh_sshd_config 4 | - name: Collect OS-specific variables 5 | include_vars: "{{ item }}" 6 | with_first_found: 7 | - "{{ ansible_os_family | lower }}.yml" 8 | - "{{ ansible_distribution | lower }}.yml" 9 | - default.yml 10 | 11 | - name: Set sshd_config options (group) 12 | lineinfile: 13 | dest: "{{ ssh_config_dir }}/sshd_config" 14 | line: "{{ item.option }} {{ item.value }}" 15 | regexp: "^{{ item.option }} " 16 | state: present 17 | backup: yes 18 | with_galaxyproject.general.inheritance_chain: sshd_config 19 | notify: 20 | - reload sshd 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Collection - galaxyproject.general 2 | 3 | A collection of simple Ansible roles for common (mostly system) tasks. 4 | 5 | These roles are not intended for production or community use at this time. They are a conversion to the collection 6 | format from the previous [git submodules](https://github.com/galaxyproject/ansible-collection-general/tree/submodule) 7 | used internally by the [usegalaxy-playbook](https://github.com/galaxyproject/usegalaxy-playbook) and 8 | [infrastructure-playbook](https://github.com/galaxyproject/infrastructure-playbook) playbooks. 9 | 10 | ## Usage 11 | 12 | ```console 13 | ansible-galaxy collection install galaxyproject.general 14 | ``` 15 | -------------------------------------------------------------------------------- /roles/supervisor/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | supervisord_install: virtualenv 4 | supervisord_prefix: /opt/supervisor 5 | supervisord_conf_path: /etc/supervisord.conf 6 | supervisord_conf_dir: /etc/opt/supervisor 7 | supervisord_log_dir: /var/log/supervisord 8 | supervisord_run_dir: /var/run 9 | supervisord_sock_path: "{{ supervisord_run_dir }}/supervisor.sock" 10 | supervisord_conf_ext: conf 11 | supervisord_service_install: true 12 | 13 | # this is run by cron 14 | supervisord_unprivileged_command: "{ date; pgrep -u {{ ansible_user }} supervisord || '{{ supervisord_prefix }}/bin/supervisord' -c '{{ supervisord_conf_path }}'; } >> {{ supervisord_log_dir }}/supervisord-launch.log 2>&1" 15 | -------------------------------------------------------------------------------- /roles/virtual/tasks/amazon-ec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install nvme-cli on EC2 instances 4 | include_role: 5 | name: packages 6 | vars: 7 | override_packages: 8 | - nvme-cli 9 | 10 | - name: Install EC2 udev script 11 | copy: 12 | src: ebs-nvme-mapping.sh 13 | dest: /sbin/ebs-nvme-mapping.sh 14 | mode: "0755" 15 | notify: 16 | - trigger udevd 17 | 18 | - name: Install EC2 udev rule 19 | copy: 20 | content: | 21 | SUBSYSTEM=="block", KERNEL=="nvme[0-9]*n[0-9]*", ATTRS{model}=="Amazon Elastic Block Store", PROGRAM+="/sbin/ebs-nvme-mapping.sh /dev/%k" SYMLINK+="%c" 22 | dest: /etc/udev/rules.d/999-aws-ebs-nvme.rules 23 | notify: 24 | - trigger udevd 25 | -------------------------------------------------------------------------------- /roles/packages/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all_packages: [] 4 | group_packages: [] 5 | host_packages: [] 6 | all_apt_repositories: [] 7 | group_apt_repositories: [] 8 | host_apt_repositories: [] 9 | all_apt_keys: [] 10 | group_apt_keys: [] 11 | host_apt_keys: [] 12 | all_yum_repositories: [] 13 | group_yum_repositories: [] 14 | host_yum_repositories: [] 15 | 16 | install_scl: false 17 | install_epel: false 18 | powertools_repo_file: 19 | EL: CentOS-Linux-PowerTools.repo 20 | CentOS: CentOS-Linux-PowerTools.repo 21 | Rocky: Rocky-PowerTools.repo 22 | AlmaLinux: almalinux-powertools.repo 23 | crb_repo_file: 24 | EL: centos.repo 25 | CentOS: centos.repo 26 | Rocky: rocky.repo 27 | AlmaLinux: almalinux-crb.repo 28 | -------------------------------------------------------------------------------- /roles/systemd/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reload systemd 4 | ansible.builtin.systemd: 5 | daemon_reload: true 6 | 7 | - name: reload journald 8 | ansible.builtin.systemd: 9 | name: systemd-journald.service 10 | state: restarted 11 | 12 | - name: restart changed systemd services 13 | service: 14 | name: "{{ item.item.name }}.service" 15 | state: restarted 16 | with_items: "{{ __systemd_resource_controls_result.results + __systemd_overrides_result.results }}" 17 | when: "item.changed and (item.item.unit_type | default('service') | lower == 'service') and (item.item.restart_on_change | default(true))" 18 | loop_control: 19 | label: "{{ item.item.name }}.{{ item.item.unit_type | default('service') | lower }}" 20 | -------------------------------------------------------------------------------- /roles/cron/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Schedule cron jobs 4 | cron: 5 | name: "{{ item.name | default(item.id) }}" 6 | cron_file: "{{ (item.use_cron_file | default(true)) | ternary('ansible_cron_' ~ item.id if ansible_os_family != 'Solaris' else 'crontabs/' ~ item.user, omit) }}" 7 | user: "{{ item.user | default(omit) }}" 8 | hour: "{{ item.hour | default(omit) }}" 9 | minute: "{{ item.minute | default(omit) }}" 10 | day: "{{ item.day | default(omit) }}" 11 | month: "{{ item.month | default(omit) }}" 12 | weekday: "{{ item.weekday | default(omit) }}" 13 | job: "{{ item.job }}" 14 | state: "{{ item.state | default(omit) }}" 15 | with_galaxyproject.general.inheritance_chain: "crontabs" 16 | notify: refresh cron 17 | -------------------------------------------------------------------------------- /roles/resolv/tasks/linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Check for dhclient 4 | command: pgrep dhclient 5 | register: dhclient 6 | failed_when: false 7 | changed_when: false 8 | 9 | - name: Install resolv.conf 10 | template: 11 | src: resolv.conf.j2 12 | dest: /etc/resolv.conf 13 | mode: 0444 14 | backup: yes 15 | when: dhclient.rc == 1 16 | 17 | # Ideally we do this first, but it can fail if DNS is broken since the module automatically installs python3-apt: 18 | # [WARNING]: Updating cache and auto-installing missing dependency: python3-apt 19 | - name: Uninstall resolvconf 20 | apt: 21 | name: resolvconf 22 | state: absent 23 | purge: yes 24 | when: ansible_lsb is defined and 'id' in ansible_lsb and ansible_lsb.id == "Ubuntu" 25 | -------------------------------------------------------------------------------- /roles/openstack/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include_tasks: jump_host.yml 4 | when: os_jump_host is defined 5 | 6 | - name: Secrets block 7 | block: 8 | 9 | - include_tasks: secrets.yml 10 | when: openstack_manage_secrets 11 | 12 | - include_tasks: initialize.yml 13 | when: 14 | - os_network is defined 15 | - os_security_group_rules is defined 16 | 17 | - include_tasks: spawn.yml 18 | when: 19 | - os_image is defined 20 | - os_flavor is defined 21 | - os_key_name is defined 22 | - os_nics is defined 23 | - os_security_groups is defined 24 | 25 | always: 26 | 27 | - include_tasks: clean.yml 28 | when: openstack_manage_secrets 29 | 30 | rescue: 31 | 32 | - fail: 33 | msg: Exiting due to previous failure 34 | -------------------------------------------------------------------------------- /roles/virtual/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Gather EC2 facts 4 | amazon.aws.ec2_metadata_facts: 5 | when: (ansible_system_vendor | default(none)) == "Amazon EC2" 6 | 7 | - name: Set hostname 8 | ansible.builtin.hostname: 9 | name: "{{ inventory_hostname }}" 10 | use: "{{ hostname_strategy | default(omit) }}" 11 | when: hostname_strategy is not defined or (hostname_strategy is defined and hostname_strategy != "file") 12 | 13 | # TODO: I think these tasks aren't necessary anymore, drop if true 14 | #- name: Include Amazon EC2 tasks 15 | # include_tasks: amazon-ec2.yml 16 | # when: ansible_system_vendor == "Amazon EC2" 17 | 18 | - name: Include SmartOS LX Brand tasks 19 | ansible.builtin.include_tasks: lx-brand.yml 20 | when: 21 | - ansible_system == "Linux" 22 | - ansible_virtualization_type == "zone" or ansible_kernel_version == "BrandZ virtual linux" 23 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/package.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Set variables appropriate for package install type 4 | include_vars: "{{ ansible_os_family | lower }}_package.yml" 5 | 6 | - name: Install supervisor (apt) 7 | apt: 8 | name: supervisor 9 | when: ansible_os_family == "Debian" 10 | 11 | - name: Install supervisor (yum) 12 | yum: 13 | name: supervisor 14 | when: ansible_os_family == "RedHat" 15 | 16 | - name: Add inet options if set 17 | copy: 18 | content: | 19 | [inet_http_server] 20 | port = {{ supervisord_inet_listen }}:{{ supervisord_inet_port }} 21 | username = {{ supervisord_inet_user }} 22 | password = {SHA}{{ supervisord_inet_pass | hash('sha1') }} 23 | dest: "{{ supervisord_conf_dir }}/05_inet_http_server.{{ supervisord_conf_ext }}" 24 | when: supervisord_inet_listen is defined 25 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Include tasks for install type 4 | include_tasks: "{{ supervisord_install }}.yml" 5 | 6 | - name: Install supervisor configs 7 | template: 8 | src: "templates/supervisor/{{ item }}.j2" 9 | dest: "{{ supervisord_conf_dir }}/{{ item }}.{{ supervisord_conf_ext }}" 10 | with_galaxyproject.general.inheritance_chain: "supervisor_configs" 11 | notify: 12 | - update supervisord 13 | 14 | - name: Remove supervisor configs 15 | file: 16 | path: "{{ supervisord_conf_dir }}/{{ item }}.{{ supervisord_conf_ext }}" 17 | state: absent 18 | with_galaxyproject.general.inheritance_chain: "absent_supervisor_configs" 19 | notify: 20 | - update supervisord 21 | 22 | - name: Ensure supervisord is enabled and running 23 | service: 24 | name: "{{ supervisord_service_name }}" 25 | enabled: yes 26 | state: started 27 | when: supervisord_service_name is defined 28 | -------------------------------------------------------------------------------- /roles/paths/tasks/install_zfs_redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install rpm key 4 | ansible.builtin.rpm_key: 5 | key: https://raw.githubusercontent.com/zfsonlinux/zfsonlinux.github.com/master/zfs-release/RPM-GPG-KEY-openzfs-key2 6 | fingerprint: 7DC7 299D CF7C 7FD9 CD87 701B A599 FD5E 9DB8 4141 7 | 8 | - name: Install zfs-release package 9 | ansible.builtin.dnf: 10 | name: "https://zfsonlinux.org/epel/zfs-release-{{ zfs_on_linux_release_version }}.el{{ ansible_distribution_major_version }}.noarch.rpm" 11 | 12 | - name: Install dnf config-manager 13 | ansible.builtin.dnf: 14 | name: "dnf-command(config-manager)" 15 | 16 | - name: Enable correct repository for install type 17 | community.general.dnf_config_manager: 18 | name: "{{ item.name }}" 19 | state: "{{ item.state }}" 20 | loop: "{{ zfs_on_linux_repo_states }}" 21 | 22 | - name: Install zfs package 23 | ansible.builtin.dnf: 24 | name: "{{ zfs_on_linux_package_name }}" 25 | -------------------------------------------------------------------------------- /roles/users/tasks/non-solaris.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Add/remove groups (non-Solaris) 4 | group: 5 | name: "{{ item.name }}" 6 | gid: "{{ item.gid | default(omit) }}" 7 | system: "{{ item.system | default(omit) }}" 8 | state: "{{ item.state | default(omit) }}" 9 | local: "{{ item.local | default(omit) }}" 10 | with_galaxyproject.general.inheritance_chain: "groups" 11 | 12 | - name: Add/remove users (non-Solaris) 13 | user: 14 | name: "{{ item.name }}" 15 | comment: "{{ item.comment | default(omit) }}" 16 | uid: "{{ item.uid | default(omit) }}" 17 | group: "{{ item.group | default(omit) }}" 18 | groups: "{{ item.groups | default(omit) }}" 19 | home: "{{ item.home | default(omit) }}" 20 | shell: "{{ item.shell | default(omit) }}" 21 | system: "{{ item.system | default(omit) }}" 22 | state: "{{ item.state | default(omit) }}" 23 | local: "{{ item.local | default(omit) }}" 24 | with_galaxyproject.general.inheritance_chain: "users" 25 | -------------------------------------------------------------------------------- /roles/users/tasks/solaris.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Add/remove user groups (Solaris) 4 | group: 5 | name: "{{ item.group }}" 6 | gid: "{{ item.gid | default(omit) }}" 7 | system: "{{ item.system | default(omit) }}" 8 | state: "{{ item.state | default(omit) }}" 9 | with_galaxyproject.general.inheritance_chain: "users" 10 | when: item.group is defined 11 | 12 | - name: Add/remove users (Solaris) 13 | user: 14 | name: "{{ item.name }}" 15 | comment: "{{ item.comment | default(omit) }}" 16 | uid: "{{ item.uid | default(omit) }}" 17 | group: "{{ item.group | default(omit) }}" 18 | home: "{{ item.home | default(omit) }}" 19 | shell: "{{ item.shell | default(omit) }}" 20 | system: "{{ item.system | default(omit) }}" 21 | password: "{{ item.password | default('NP') }}" 22 | update_password: "{{ item.update_password | default(omit) }}" 23 | state: "{{ item.state | default(omit) }}" 24 | with_galaxyproject.general.inheritance_chain: "users" 25 | -------------------------------------------------------------------------------- /roles/ssh/tasks/smartos_zone_openssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Collect variables for OpenSSH on SmartOS 4 | include_vars: smartos_zone.yml 5 | 6 | - name: Install OpenSSH from pkgin 7 | pkgin: 8 | name: openssh 9 | 10 | - name: Set OpenSSH host keys to SunSSH host keys 11 | lineinfile: 12 | dest: "{{ ssh_config_dir }}/sshd_config" 13 | line: "HostKey {{ item }}" 14 | state: present 15 | backup: yes 16 | with_items: 17 | - /var/ssh/ssh_host_rsa_key 18 | - /var/ssh/ssh_host_dsa_key 19 | notify: 20 | - reload sshd 21 | 22 | - name: Disable motd printing 23 | lineinfile: 24 | dest: "{{ ssh_config_dir }}/sshd_config" 25 | line: "PrintMotd no" 26 | regexp: "^PrintMotd " 27 | state: present 28 | backup: yes 29 | notify: 30 | - reload sshd 31 | 32 | - name: Disable SunSSH 33 | service: 34 | name: ssh 35 | state: stopped 36 | enabled: no 37 | 38 | - name: Enable OpenSSH 39 | service: 40 | name: openssh 41 | state: started 42 | enabled: yes 43 | -------------------------------------------------------------------------------- /roles/timezone/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: timezone conditional tasks 4 | block: 5 | 6 | - name: Ensure timezone package is installed 7 | package: 8 | name: tzdata 9 | when: ansible_os_family == "Debian" 10 | 11 | - name: Set timezone (Debian) 12 | copy: 13 | content: '{{ timezone }}\n' 14 | dest: /etc/timezone 15 | mode: 0444 16 | backup: yes 17 | notify: 18 | - persist timezone on debian 19 | when: ansible_os_family == "Debian" 20 | 21 | - name: Set timezone name (RedHat) 22 | copy: 23 | content: 'ZONE="{{ timezone }}"' 24 | dest: /etc/sysconfig/clock 25 | mode: 0444 26 | when: ansible_os_family == "RedHat" 27 | 28 | - name: Set timezone zoneinfo (RedHat) 29 | file: 30 | dest: /etc/localtime 31 | src: /usr/share/zoneinfo/{{ timezone }} 32 | state: link 33 | force: yes 34 | when: ansible_os_family == "RedHat" 35 | 36 | when: timezone is defined 37 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/virtualenv-unprivileged.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install supervisor (virtualenv) 4 | pip: 5 | name: supervisor 6 | virtualenv: "{{ supervisord_prefix }}" 7 | virtualenv_command: "{{ pip_virtualenv_command | default(omit) }}" 8 | 9 | - name: Create local supervisor directories 10 | file: 11 | path: "{{ item }}" 12 | state: directory 13 | mode: 0750 14 | with_items: 15 | - "{{ supervisord_conf_dir }}" 16 | - "{{ supervisord_log_dir }}" 17 | - "{{ supervisord_run_dir }}" 18 | 19 | - name: Create cron job to start supervisord 20 | cron: 21 | name: galaxyproject.supervisord-run 22 | minute: "*/5" 23 | job: "{{ supervisord_unprivileged_command }}" 24 | state: "{{ supervisord_service_install | ternary('present', 'absent') }}" 25 | when: supervisord_unprivileged_command is not none 26 | 27 | - name: Install supervisord.conf 28 | template: 29 | src: supervisord.conf.j2 30 | dest: "{{ supervisord_conf_path }}" 31 | notify: 32 | - restart supervisord 33 | -------------------------------------------------------------------------------- /roles/firewall/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install or uninstall firewalld 4 | yum: 5 | name: firewalld 6 | state: "{{ firewalld_state }}" 7 | when: firewalld_state is defined 8 | 9 | - name: Manage firewall rules 10 | firewalld: 11 | immediate: "{{ item.immediate | default(omit) }}" 12 | interface: "{{ item.interface | default(omit) }}" 13 | masquerade: "{{ item.masquerade | default(omit) }}" 14 | permanent: "{{ item.permanent | default(omit) }}" 15 | port: "{{ item.port | default(omit) }}" 16 | rich_rule: "{{ item.rich_rule | default(omit) }}" 17 | service: "{{ item.service | default(omit) }}" 18 | source: "{{ item.source | default(omit) }}" 19 | state: "{{ item.state }}" 20 | timeout: "{{ item.timeout | default(omit) }}" 21 | zone: "{{ item.zone | default(omit) }}" 22 | with_flattened: 23 | - "{{ all_firewall_rules }}" 24 | - "{{ group_firewall_rules }}" 25 | - "{{ host_firewall_rules }}" 26 | when: ansible_os_family == "RedHat" 27 | 28 | - name: Set SELinux state 29 | selinux: 30 | state: "{{ selinux_state }}" 31 | when: "selinux_state is defined" 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Galaxy Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /roles/services/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Could do this with a parameterized role dep 4 | - name: Copy Solaris service configurations 5 | copy: 6 | backup: "{{ item.backup | default(omit) }}" 7 | content: "{{ item.content | default(omit) }}" 8 | dest: "{{ item.dest | default('/var/svc/manifest/site/' ~ item.src | basename) }}" 9 | src: "{{ item.src | default(omit) }}" 10 | register: copy_service_config_results 11 | with_flattened: 12 | - "{{ all_service_configurations }}" 13 | - "{{ group_service_configurations }}" 14 | - "{{ host_service_configurations }}" 15 | 16 | - name: Import Solaris service configurations 17 | command: /usr/sbin/svccfg import {{ item.dest }} 18 | when: item.changed 19 | with_items: "{{ copy_service_config_results.results | default('[]') }}" 20 | 21 | - name: Manage services 22 | service: 23 | name: "{{ item.name }}" 24 | pattern: "{{ item.pattern | default(omit) }}" 25 | arguments: "{{ item.arguments | default(omit) }}" 26 | sleep: "{{ item.sleep | default(omit) }}" 27 | state: "{{ item.state | default(omit) }}" 28 | enabled: "{{ item.enabled | default(omit) }}" 29 | with_flattened: 30 | - "{{ all_services }}" 31 | - "{{ group_services }}" 32 | - "{{ host_services }}" 33 | -------------------------------------------------------------------------------- /roles/ssl/tasks/gen-ca.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create CA directory 4 | file: 5 | path: "{{ ssl_dir }}" 6 | state: directory 7 | 8 | - name: Generate CA key 9 | command: openssl genrsa -out {{ ssl_dir }}/ca-key.pem 4096 10 | args: 11 | creates: "{{ ssl_dir }}/ca-key.pem" 12 | 13 | - name: Generate CA cert 14 | command: > 15 | openssl req -new -x509 -days 1095 -sha256 16 | -subj '/C={{ ssl_ca.dn.country }}/ST={{ ssl_ca.dn.state }}/L={{ ssl_ca.dn.locality }}/O={{ ssl_ca.dn.organization }}/OU={{ ssl_ca.dn.organizational_unit }}/CN={{ ssl_ca.dn.common_name }}' 17 | -key {{ ssl_dir }}/ca-key.pem 18 | -out {{ ssl_dir }}/ca.pem 19 | 20 | - name: Create vault password tempfile 21 | command: mktemp -t tmp.ansible_ssl_XXXXXXXXXX 22 | register: ssl_vaultpass_mktemp_out 23 | 24 | - block: 25 | 26 | - name: Write vault password 27 | copy: 28 | content: "{{ ssl_vault_pass }}" 29 | dest: "{{ ssl_vaultpass_mktemp_out.stdout }}" 30 | mode: "0600" 31 | 32 | - name: Vault CA key 33 | command: ansible-vault encrypt --vault-password-file={{ ssl_vaultpass_mktemp_out.stdout }} {{ ssl_dir }}/ca-key.pem 34 | 35 | always: 36 | 37 | - name: Remove vault password tempfile 38 | file: 39 | path: "{{ ssl_vaultpass_mktemp_out.stdout }}" 40 | state: absent 41 | -------------------------------------------------------------------------------- /roles/supervisor/templates/supervisord.conf.j2: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 3 | ;; 4 | 5 | ; see `echo_supervisord_conf` for details 6 | 7 | [unix_http_server] 8 | file = {{ supervisord_sock_path }} 9 | 10 | {% if supervisord_inet_listen is defined -%} 11 | [inet_http_server] 12 | port = {{ supervisord_inet_listen }}:{{ supervisord_inet_port }} 13 | username = {{ supervisord_inet_user }} 14 | password = {SHA}{{ supervisord_inet_pass | hash('sha1') }} 15 | {% endif %} 16 | 17 | [supervisord] 18 | logfile = {{ supervisord_log_dir }}/supervisord.log 19 | logfile_maxbytes = 50MB 20 | logfile_backups = 10 21 | loglevel = info 22 | pidfile = {{ supervisord_run_dir }}/supervisord.pid 23 | nodaemon = false 24 | minfds = 1024 25 | minprocs = 200 26 | 27 | [rpcinterface:supervisor] 28 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 29 | 30 | [supervisorctl] 31 | serverurl = unix://{{ supervisord_sock_path }} 32 | 33 | [include] 34 | files = {{ supervisord_conf_dir }}/*.{{ supervisord_conf_ext }} 35 | -------------------------------------------------------------------------------- /roles/locale/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Locale tasks 4 | block: 5 | 6 | - name: Install debconf packages 7 | apt: 8 | name: 9 | - debconf 10 | - debconf-utils 11 | 12 | - name: Set debconf options for default locale 13 | debconf: 14 | name: locales 15 | question: "{{ item.question }}" 16 | value: "{{ item.value }}" 17 | vtype: "{{ item.vtype }}" 18 | loop: 19 | - question: "locales/locales_to_be_generated" 20 | value: "{{ default_locale }} {{ default_locale.split('.')[-1] }}" 21 | vtype: "multiselect" 22 | - question: "locales/default_environment_locale" 23 | value: "{{ default_locale }}" 24 | vtype: "select" 25 | notify: 26 | - reconfigure locales 27 | 28 | - name: Install locales package 29 | apt: 30 | name: locales 31 | 32 | - name: Ensure default locale is generated 33 | locale_gen: 34 | name: "{{ default_locale }}" 35 | notify: 36 | - reconfigure locales 37 | 38 | - name: Ensure default locale is set 39 | lineinfile: 40 | dest: "/etc/default/locale" 41 | regexp: "^LANG=" 42 | line: "LANG={{ default_locale }}" 43 | notify: 44 | - reconfigure locales 45 | 46 | - name: Flush handlers 47 | meta: flush_handlers 48 | 49 | when: ansible_os_family == "Debian" and default_locale is defined 50 | -------------------------------------------------------------------------------- /roles/ssh/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/ssl/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/copy/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/cron/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/firewall/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/locale/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/packages/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/paths/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/resolv/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/services/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/systemd/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/timezone/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/users/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/virtual/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/ceph_mount/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/kernel_params/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/login_defs/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/openstack/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/required_vars/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/requiretty/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/supervisor/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/remote_management/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | MIT 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/openstack/tasks/initialize.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create network 4 | openstack.cloud.network: 5 | cloud: "{{ os_cloud_id }}" 6 | name: "{{ os_network.name }}" 7 | delegate_to: localhost 8 | run_once: true 9 | 10 | - name: Create subnet 11 | openstack.cloud.subnet: 12 | network_name: "{{ os_network.name }}" 13 | name: "{{ os_network.subnet.name }}" 14 | cidr: "{{ os_network.subnet.cidr }}" 15 | delegate_to: localhost 16 | run_once: true 17 | 18 | - name: Create router 19 | openstack.cloud.router: 20 | name: "{{ os_network.router.name }}" 21 | network: "{{ os_network.router.network }}" 22 | interfaces: "{{ os_network.router.interfaces }}" 23 | delegate_to: localhost 24 | run_once: true 25 | 26 | - name: Create security groups 27 | openstack.cloud.security_group: 28 | cloud: "{{ os_cloud_id }}" 29 | name: "{{ item.name }}" 30 | loop: "{{ os_security_group_rules }}" 31 | delegate_to: localhost 32 | run_once: true 33 | 34 | - name: Create security group rules 35 | openstack.cloud.security_group_rule: 36 | cloud: "{{ os_cloud_id }}" 37 | security_group: "{{ item.0.name }}" 38 | protocol: "{{ item.1.protocol | default(omit) }}" 39 | remote_ip_prefix: "{{ item.1.remote_ip_prefix | default(omit) }}" 40 | port_range_min: "{{ item.1.port_range_min | default(omit) }}" 41 | port_range_max: "{{ item.1.port_range_max | default(omit) }}" 42 | loop: "{{ os_security_group_rules | subelements('rules') }}" 43 | delegate_to: localhost 44 | run_once: true 45 | -------------------------------------------------------------------------------- /roles/required_vars/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # in lieu of a config lookup, which should exist some day, look up roles_path in ansible.cfg 4 | 5 | # there doesn't seem to be a variables for these things, this is *really* hacky and only works for our playbook structure 6 | - name: Get top level directory 7 | set_fact: 8 | cwd: "{{ playbook_dir ~ '/../..' }}" 9 | 10 | - name: Find required vars files 11 | stat: 12 | path: "{{ cwd }}/{{ item.0 }}/{{ item.1 }}/meta/required_vars.yml" 13 | with_nested: 14 | - "{{ lookup('ini', 'roles_path section=defaults file=' ~ cwd ~ '/ansible.cfg').split(':') | default(['roles']) | reverse | list }}" 15 | - "{{ required_vars_roles | default([]) }}" 16 | delegate_to: localhost 17 | register: _ret_required_vars_stat 18 | 19 | # item.item = [ role_dir, role_name ] 20 | - name: Read required vars files 21 | set_fact: 22 | required_vars: "{{ required_vars | default({}) | combine({item.item[1]: {'name': item.item[1], 'vars': lookup('file', item.stat.path) | from_yaml}}) }}" 23 | with_items: "{{ _ret_required_vars_stat.results }}" 24 | loop_control: 25 | label: "{{ item.item | join('/') }}" 26 | when: item.stat.exists 27 | delegate_to: localhost 28 | register: _ret_required_vars 29 | 30 | # note "skipped" here will mean the var is defined 31 | - name: Fail if required vars are undefined 32 | fail: 33 | msg: "Required variable {{ item.1 }} of role {{ item.0.name }} is not defined" 34 | with_subelements: 35 | - "{{ required_vars }}" 36 | - vars 37 | loop_control: 38 | label: "{{ item.1 }}" 39 | when: item.1 not in vars 40 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/virtualenv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Set variables appropriate for virtualenv install type 4 | include_vars: virtualenv.yml 5 | 6 | - name: Install virtualenv (apt) 7 | apt: 8 | name: python-virtualenv 9 | when: ansible_os_family == "Debian" 10 | 11 | - name: Install virtualenv (yum) 12 | yum: 13 | name: python-virtualenv 14 | when: ansible_os_family == "RedHat" 15 | 16 | - name: Install supervisor (virtualenv) 17 | pip: 18 | name: supervisor 19 | virtualenv: "{{ supervisord_prefix }}" 20 | virtualenv_command: "{{ pip_virtualenv_command | default(omit) }}" 21 | 22 | - name: Create local supervisor directories 23 | file: 24 | path: "{{ item }}" 25 | state: directory 26 | with_items: 27 | - "{{ supervisord_conf_dir }}" 28 | - "{{ supervisord_log_dir }}" 29 | 30 | - name: Install supervisord.conf 31 | template: 32 | src: supervisord.conf.j2 33 | dest: "{{ supervisord_conf_path }}" 34 | notify: 35 | - restart supervisord 36 | 37 | - name: supervisord service install block 38 | block: 39 | 40 | - name: Detect systemd 41 | command: /usr/bin/pgrep -u root systemd 42 | register: systemd 43 | failed_when: False 44 | changed_when: False 45 | 46 | - name: Install init script (SysV init) 47 | template: 48 | src: "{{ ansible_distribution | lower }}.init.j2" 49 | dest: /etc/init.d/supervisor 50 | mode: "0755" 51 | when: systemd.rc != 0 52 | 53 | - name: Install service unit file (systemd) 54 | template: 55 | src: systemd.init.j2 56 | dest: /etc/systemd/system/supervisor.service 57 | mode: "0755" 58 | when: systemd.rc == 0 59 | 60 | when: supervisord_service_install 61 | -------------------------------------------------------------------------------- /roles/systemd/templates/resource_controls.conf.j2: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This file is managed by Ansible. ALL CHANGES WILL BE OVERWRITTEN. 3 | ;; 4 | {% if item.real_memory_limit is defined %} 5 | {% set memlim = item.real_memory_limit %} 6 | {% elif item.real_memory_limit_percent is defined and item.real_memory_limit_percent > 1.0 %} 7 | {% set memlim = ((item.real_memory_limit_percent / 100.0) * ansible_memory_mb.real.total) | int ~ "M" %} 8 | {% elif item.real_memory_limit_percent is defined %} 9 | {% set memlim = (item.real_memory_limit_percent * ansible_memory_mb.real.total) | int ~ "M" %} 10 | {% else %} 11 | {% set memlim = none %} 12 | {% endif -%} 13 | 14 | {%- set memlim_mb = memlim | default(ansible_memory_mb.real.total * 1024 * 1024) | human_to_bytes / 1024 // 1024 %} 15 | {% if item.swap_limit is defined %} 16 | {% set swlim_mb = (item.swap_limit | human_to_bytes / 1024 // 1024) | int %} 17 | {% elif item.swap_limit_percent is defined and item.swap_limit_percent > 1.0 %} 18 | {% set swlim_mb = ((item.swap_limit_percent / 100.0) * ansible_memory_mb.swap.total) | int %} 19 | {% elif item.swap_limit_percent is defined %} 20 | {% set swlim_mb = (item.swap_limit_percent * ansible_memory_mb.swap.total) | int %} 21 | {% else %} 22 | {% set swlim_mb = none %} 23 | {% endif -%} 24 | 25 | [{{ item.unit_type | default("service") | title }}] 26 | {% if __systemd_cgroup_version == "v2" %} 27 | {% if memlim is not none %} 28 | MemoryMax={{ memlim }} 29 | {% endif %} 30 | {% if swlim_mb is not none %} 31 | MemorySwapMax={{ swlim_mb }}M" 32 | {% endif %} 33 | {% else %} 34 | {% if memlim is not none %} 35 | MemoryLimit={{ memlim }} 36 | {% endif %} 37 | {% if swlim_mb is not none %} 38 | ExecStartPost=/bin/bash -c "echo {{ memlim_mb + swlim_mb }}M > /sys/fs/cgroup/memory/system.slice/{{ item.name }}.{{ item.unit_type | default('service') | lower }}/memory.memsw.limit_in_bytes" 39 | {% endif %} 40 | {% endif %} 41 | -------------------------------------------------------------------------------- /roles/virtual/tasks/lx-brand.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: SmartOS LX Brand hostname tasks 4 | block: 5 | 6 | # Annoyingly, the builtin hostname module supports this via FileStrategy, but doesn't expose its functionalty 7 | # through the very limited set of `use` params you can choose from 8 | 9 | - name: Set hostname (immediate) 10 | command: "hostname {{ inventory_hostname }}" 11 | changed_when: false 12 | 13 | - name: Set hostname (persistent) 14 | copy: 15 | content: "{{ inventory_hostname }}" 16 | dest: /etc/hostname 17 | mode: "0755" 18 | 19 | when: (hostname_strategy | default(none)) == "file" 20 | 21 | - name: SmartOS LX Brand Debian tasks 22 | block: 23 | 24 | # I don't believe this is still necessary 25 | #- name: Hold back systemd 26 | # dpkg_selections: 27 | # name: systemd 28 | # selection: hold 29 | 30 | # sendfile bug fixed in https://github.com/joyent/illumos-joyent/commit/b189ef943db9b29af9068d3b3b49bc364699da56 20200910T013122Z 31 | 32 | # resolv.conf is not maintained in newer manually-updated LX Brand Ubuntu zones 33 | - name: Include resolv role for Ubuntu LX Brand zones 34 | include_role: 35 | name: resolv 36 | when: ansible_distribution == "Ubuntu" and ansible_distribution_version is version('18.04', '>=') 37 | 38 | - name: Create native ZFS mount-all service 39 | copy: 40 | src: zfs-mount.service 41 | dest: /etc/systemd/system/zfs-mount.service 42 | mode: "0644" 43 | 44 | - name: Enable native ZFS mount-all service 45 | systemd: 46 | name: zfs-mount.service 47 | enabled: true 48 | 49 | when: ansible_os_family == "Debian" 50 | 51 | - name: SmartOS LX Brand Enterprise Linux tasks 52 | block: 53 | 54 | - name: Disable services 55 | ansible.builtin.systemd: 56 | name: "{{ item }}" 57 | state: stopped 58 | enabled: false 59 | loop: "{{ virtual_lx_disable_services_redhat[ansible_distribution_major_version] }}" 60 | 61 | when: ansible_os_family == "RedHat" 62 | -------------------------------------------------------------------------------- /roles/systemd/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Create unit directory for services" 4 | ansible.builtin.file: 5 | path: "/etc/systemd/system/{{ item.name }}.{{ item.unit_type | default('service') | lower }}.d" 6 | state: directory 7 | owner: root 8 | group: root 9 | mode: "0755" 10 | with_galaxyproject.general.inheritance_chain: 11 | - "systemd_resource_controls" 12 | - "systemd_overrides" 13 | 14 | - name: "Slurp supported filesystems" 15 | ansible.builtin.slurp: 16 | src: /proc/filesystems 17 | register: __systemd_filesystems 18 | 19 | - name: "Set cgroup version fact" 20 | ansible.builtin.set_fact: 21 | __systemd_cgroup_version: "{{ (__systemd_filesystems['content'] | b64decode | regex_findall('^nodev\\s+cgroup2$', multiline=True) is truthy) | ternary('v2', 'v1') }}" 22 | 23 | - name: "Create unit files for resource controlled units" 24 | ansible.builtin.template: 25 | src: resource_controls.conf.j2 26 | dest: "/etc/systemd/system/{{ item.name }}.{{ item.unit_type | default('service') | lower }}.d/ansible_resource_controls.conf" 27 | owner: root 28 | group: root 29 | mode: "0444" 30 | with_galaxyproject.general.inheritance_chain: "systemd_resource_controls" 31 | register: __systemd_resource_controls_result 32 | notify: 33 | - reload systemd 34 | - restart changed systemd services 35 | 36 | - name: "Create unit files for override units" 37 | ansible.builtin.template: 38 | src: overrides.conf.j2 39 | dest: "/etc/systemd/system/{{ item.name }}.{{ item.unit_type | default('service') | lower }}.d/ansible_overrides.conf" 40 | owner: root 41 | group: root 42 | mode: "0444" 43 | with_galaxyproject.general.inheritance_chain: "systemd_overrides" 44 | register: __systemd_overrides_result 45 | notify: 46 | - reload systemd 47 | - restart changed systemd services 48 | 49 | - name: Create persistent journald directory 50 | ansible.builtin.file: 51 | path: /var/log/journal 52 | state: directory 53 | owner: root 54 | group: systemd-journal 55 | mode: "2755" 56 | when: "{{ systemd_journald_persistent | default(false) }}" 57 | notify: 58 | - reload journald 59 | -------------------------------------------------------------------------------- /roles/users/tasks/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Merge inheritance chain variables 4 | set_fact: 5 | common_authorized_key_users: "{{ lookup('galaxyproject.general.inheritance_chain', 'authorized_key_users') | galaxyproject.general.subelement_union('name', 'authorized') }}" 6 | common_private_key_users: "{{ lookup('galaxyproject.general.inheritance_chain', 'private_key_users') | galaxyproject.general.subelement_union('name', 'keys') }}" 7 | 8 | - name: Ensure home directories exist for authorized/private keys 9 | user: 10 | name: "{{ item.name }}" 11 | createhome: yes 12 | with_items: "{{ common_authorized_key_users + common_private_key_users }}" 13 | loop_control: 14 | label: "{{ item.name }}" 15 | 16 | - name: Set authorized keys 17 | authorized_key: 18 | user: "{{ item.name }}" 19 | key: "{% for authorized in item.authorized %}{{ ssh_public_keys[authorized] ~ '\n' }}{% endfor %}" 20 | exclusive: "{{ item.exclusive | default('yes') }}" 21 | with_items: "{{ common_authorized_key_users }}" 22 | 23 | # Still need to do this for the group ownership of .ssh and keys themselves until Ansible has a way to do this or we write a private key module 24 | - name: Collect user groups for private keys 25 | command: id -gn {{ item.name }} 26 | with_items: "{{ common_private_key_users }}" 27 | changed_when: no 28 | register: private_key_groups_out 29 | 30 | - name: Set user group fact 31 | set_fact: 32 | private_key_user_groups: "{{ (private_key_user_groups | default({})) | combine({item.item.name: item.stdout}) }}" 33 | with_items: "{{ private_key_groups_out.results }}" 34 | 35 | - name: Ensure ~/.ssh directories exist for installing private keys 36 | file: 37 | path: "~{{ item.name }}/.ssh" 38 | state: directory 39 | owner: "{{ item.name }}" 40 | group: "{{ private_key_user_groups[item.name] }}" 41 | with_items: "{{ common_private_key_users }}" 42 | 43 | - name: Install private keys 44 | copy: 45 | content: "{{ ssh_private_keys[item.1.key] }}" 46 | dest: "~{{ item.0.name }}/.ssh/{{ item.1.file }}" 47 | owner: "{{ item.0.name }}" 48 | group: "{{ private_key_user_groups[item.0.name] }}" 49 | mode: 0600 50 | with_subelements: 51 | - "{{ common_private_key_users }}" 52 | - keys 53 | 54 | - name: Install known hosts 55 | known_hosts: 56 | name: "{{ item.name }}" 57 | key: "{{ item.key }}" 58 | path: "{{ item.path }}" 59 | state: "{{ item.state | default(omit) }}" 60 | with_galaxyproject.general.inheritance_chain: "known_hosts" 61 | -------------------------------------------------------------------------------- /roles/ssl/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Include SSL CA tasks 4 | include_tasks: ca.yml 5 | vars: 6 | ssl_dir: "{{ inventory_dir }}/files/ssl{{ '/' ~ cert_item.ca | default('') }}" 7 | ssl_ca: "{{ ssl_cas[cert_item.ca] | default('') }}" 8 | ssl_cert: "{{ cert_item }}" 9 | ssl_cert_def: "{{ ssl_cas[cert_item.ca].certs[cert_item.name] | default('') }}" 10 | #serial: 1 # basically used for locking purposes 11 | with_flattened: 12 | - "{{ ssl_role_certs | default([]) }}" # for use with the include_role task 13 | - "{{ ssl_all_certs | default([]) }}" 14 | - "[{% for group_name in group_names %}{{ vars['ssl_' ~ group_name ~ '_group_certs'] ~ ', ' if 'ssl_' ~ group_name ~ '_group_certs' in vars else None }}{% endfor %}]" 15 | - "{{ ssl_host_certs | default([]) }}" 16 | loop_control: 17 | loop_var: cert_item 18 | when: ssl_cas[cert_item.ca] is defined 19 | 20 | - name: Include SSL cert tasks 21 | include_tasks: cert.yml 22 | vars: 23 | ssl_dir: "{{ inventory_dir }}/files/ssl{{ '/' ~ cert_item.ca | default('') }}" 24 | ssl_cert_dir: "{{ ssl_dir }}{{ '/' ~ inventory_hostname if cert_item.per_host is defined and cert_item.per_host else '' }}" 25 | ssl_ca: "{{ ssl_cas[cert_item.ca] | default('') }}" 26 | ssl_cert: "{{ cert_item }}" 27 | ssl_cert_def: "{{ ssl_cas[cert_item.ca].certs[cert_item.name] | default('') }}" 28 | with_flattened: 29 | - "{{ ssl_role_certs | default([]) }}" 30 | - "{{ ssl_all_certs | default([]) }}" 31 | - "[{% for group_name in group_names %}{{ vars['ssl_' ~ group_name ~ '_group_certs'] ~ ', ' if 'ssl_' ~ group_name ~ '_group_certs' in vars else None }}{% endfor %}]" 32 | - "{{ ssl_host_certs | default([]) }}" 33 | loop_control: 34 | loop_var: cert_item 35 | when: ssl_cas[cert_item.ca] is defined 36 | 37 | - name: Load private keys 38 | include_vars: 39 | dir: "{{ inventory_dir }}/files/ssl/" 40 | files_matching: ".*_privatekey.yml$" 41 | name: ssl_keys 42 | 43 | - name: Distribute certs 44 | include_tasks: distribute.yml 45 | vars: 46 | ssl_dir: "{{ inventory_dir }}/files/ssl{{ '/' ~ cert_item.ca | default('') }}" 47 | ssl_cert_dir: "{{ ssl_dir }}{{ '/' ~ inventory_hostname if cert_item.per_host is defined and cert_item.per_host else '' }}" 48 | ssl_cert: "{{ cert_item }}" 49 | with_flattened: 50 | - "{{ ssl_role_certs | default([]) }}" 51 | - "{{ ssl_all_certs | default([]) }}" 52 | - "[{% for group_name in group_names %}{{ vars['ssl_' ~ group_name ~ '_group_certs'] ~ ', ' if 'ssl_' ~ group_name ~ '_group_certs' in vars else None }}{% endfor %}]" 53 | - "{{ ssl_host_certs | default([]) }}" 54 | loop_control: 55 | loop_var: cert_item 56 | -------------------------------------------------------------------------------- /plugins/lookup/inheritance_chain.py: -------------------------------------------------------------------------------- 1 | from __future__ import (absolute_import, division, print_function) 2 | __metaclass__ = type 3 | 4 | 5 | DOCUMENTATION = """ 6 | """ 7 | 8 | EXAMPLES = """ 9 | """ 10 | 11 | RETURN = """ 12 | """ 13 | 14 | 15 | from ansible.errors import AnsibleError 16 | from ansible.plugins.lookup import LookupBase 17 | 18 | try: 19 | from __main__ import display 20 | except ImportError: 21 | from ansible.utils.display import Display 22 | display = Display() 23 | 24 | 25 | class LookupModule(LookupBase): 26 | def __chain_for_base(self, base, _vars): 27 | r = None 28 | if 'override_' + base in _vars: 29 | prefixes = ['override'] 30 | else: 31 | prefixes = ['all', 'group', 'host'] 32 | prefixes[2:2] = [n.replace('-', '_') + '_group' for n in _vars['group_names']] 33 | for prefix in prefixes: 34 | _var = prefix + '_' + base 35 | _val = _vars.get(_var, None) 36 | if _val: 37 | display.vvvv(f'{_var} = {_val}') 38 | try: 39 | t = self._templar.template( 40 | _vars.get(_var, None), preserve_trailing_newlines=True, 41 | convert_data=True, escape_backslashes=False) 42 | except Exception as exc: 43 | raise AnsibleError(f"Templating '{_var}' failed: {exc}") 44 | if t != _val: 45 | display.vvvv(f'{_var} -> {t}') 46 | if t is None: 47 | continue 48 | if isinstance(t, dict): 49 | if r is None: 50 | r = {} 51 | r.update(t) 52 | elif isinstance(t, list): 53 | if r is None: 54 | r = [] 55 | r.extend(t) 56 | else: 57 | raise AnsibleError(f"Unknown type of '{_var}': {type(t)}") 58 | return r 59 | 60 | def run(self, terms, variables=None, **kwargs): 61 | try: 62 | assert 'group_names' in variables, "Missing 'group_names' in variables" 63 | assert len(terms) >= 1, f"Inheritance chain lookup plugin expects 1 or more terms, got {len(terms)}" 64 | except AssertionError as exc: 65 | raise AnsibleError(str(exc)) 66 | _vars = variables or {} 67 | r = None 68 | for base in terms: 69 | _r = self.__chain_for_base(base, _vars) 70 | if isinstance(_r, dict): 71 | if r is None: 72 | r = {} 73 | r.update(_r) 74 | elif isinstance(_r, list): 75 | if r is None: 76 | r = [] 77 | r.extend(_r) 78 | if isinstance(r, dict): 79 | r = [r] 80 | return r or [] 81 | -------------------------------------------------------------------------------- /roles/ssl/tasks/distribute.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create CA cert directories 4 | file: 5 | path: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].ca_cert | dirname }}" 6 | state: directory 7 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 8 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 9 | when: item[0].ca_cert is defined 10 | with_nested: 11 | - "{{ ssl_cert.paths }}" 12 | - "{{ ssl_cert.users | default(['']) }}" 13 | 14 | - name: Distribute CA cert 15 | copy: 16 | src: "{{ ssl_dir }}/ca.pem" 17 | dest: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].ca_cert }}" 18 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 19 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 20 | mode: "0444" 21 | when: item[0].ca_cert is defined 22 | with_nested: 23 | - "{{ ssl_cert.paths }}" 24 | - "{{ ssl_cert.users | default(['']) }}" 25 | 26 | - name: Create cert directories 27 | file: 28 | path: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].cert | dirname }}" 29 | state: directory 30 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 31 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 32 | with_nested: 33 | - "{{ ssl_cert.paths }}" 34 | - "{{ ssl_cert.users | default(['']) }}" 35 | 36 | - name: Distribute cert 37 | copy: 38 | src: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}.pem" 39 | dest: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].cert }}" 40 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 41 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 42 | mode: "0444" 43 | with_nested: 44 | - "{{ ssl_cert.paths }}" 45 | - "{{ ssl_cert.users | default(['']) }}" 46 | 47 | - name: Create key directories 48 | file: 49 | path: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].key | dirname }}" 50 | state: directory 51 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 52 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 53 | with_nested: 54 | - "{{ ssl_cert.paths }}" 55 | - "{{ ssl_cert.users | default(['']) }}" 56 | 57 | - name: Set private key var name 58 | set_fact: 59 | ssl_key_var_name: "{{ ssl_cert.ca }}{{ '_' ~ inventory_hostname if ssl_cert.per_host is defined and ssl_cert.per_host else '' }}_{{ ssl_cert.name }}" 60 | 61 | - name: Distribute key 62 | copy: 63 | content: "{{ ssl_keys[ssl_key_var_name] }}" 64 | dest: "{{ '~' ~ item[1] ~ '/' if item[1] else '' }}{{ item[0].key }}" 65 | owner: "{{ ssl_cert.owner | default(omit) if not item[1] else item[1] }}" 66 | group: "{{ ssl_cert.group | default(omit) if not item[1] else omit }}" 67 | mode: "0400" 68 | with_nested: 69 | - "{{ ssl_cert.paths }}" 70 | - "{{ ssl_cert.users | default(['']) }}" 71 | -------------------------------------------------------------------------------- /galaxy.yml: -------------------------------------------------------------------------------- 1 | ### REQUIRED 2 | # The namespace of the collection. This can be a company/brand/organization or product namespace under which all 3 | # content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with 4 | # underscores or numbers and cannot contain consecutive underscores 5 | namespace: galaxyproject 6 | 7 | # The name of the collection. Has the same character restrictions as 'namespace' 8 | name: general 9 | 10 | # The version of the collection. Must be compatible with semantic versioning 11 | version: 1.4.1 12 | 13 | # The path to the Markdown (.md) readme file. This path is relative to the root of the collection 14 | readme: README.md 15 | 16 | # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) 17 | # @nicks:irc/im.site#channel' 18 | authors: 19 | - Nate Coraor 20 | 21 | 22 | ### OPTIONAL but strongly recommended 23 | # A short summary description of the collection 24 | description: Small, general purpose roles for mostly system tasks 25 | 26 | # Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only 27 | # accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' 28 | license: 29 | #- GPL-2.0-or-later 30 | 31 | # The path to the license file for the collection. This path is relative to the root of the collection. This key is 32 | # mutually exclusive with 'license' 33 | license_file: 'LICENSE' 34 | 35 | # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character 36 | # requirements as 'namespace' and 'name' 37 | tags: [] 38 | 39 | # Collections that this collection requires to be installed for it to be usable. The key of the dict is the 40 | # collection label 'namespace.name'. The value is a version range 41 | # L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version 42 | # range specifiers can be set and are separated by ',' 43 | dependencies: {} 44 | 45 | # The URL of the originating SCM repository 46 | repository: https://github.com/galaxyproject/ansible-collection-general/ 47 | 48 | # The URL to any online docs 49 | documentation: https://github.com/galaxyproject/ansible-collection-general/ 50 | 51 | # The URL to the homepage of the collection/project 52 | homepage: https://galaxyproject.org 53 | 54 | # The URL to the collection issue tracker 55 | issues: https://github.com/galaxyproject/ansible-collection-general/issues 56 | 57 | # A list of file glob-like patterns used to filter any files or directories that should not be included in the build 58 | # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This 59 | # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', 60 | # and '.git' are always filtered 61 | build_ignore: [] 62 | 63 | -------------------------------------------------------------------------------- /plugins/filter/inheritance_utils.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from functools import partial 3 | from itertools import chain 4 | 5 | from ansible.errors import AnsibleError 6 | 7 | 8 | def subelement_union(chain, key, subkey): 9 | # this will not merge any keys other than subkey, and subkey must be a list 10 | r = OrderedDict() 11 | # if a lookup plugin is called in the variable context and returns a 12 | # one-element list, the return value is replaced with the element 13 | chain = [chain] if not isinstance(chain, list) else chain 14 | for d in chain: 15 | if d[key] in r: 16 | r[d[key]][subkey].extend(filter(lambda i: i not in r[d[key]][subkey], d[subkey])) 17 | else: 18 | r[d[key]] = d 19 | return list(r.values()) 20 | 21 | 22 | def _try_keys(i, kk, vk): 23 | try: 24 | if isinstance(i, list): 25 | # will raise IndexError if it's missing an element 26 | return (i[0], i[1]) 27 | if isinstance(i, dict) and len(i) != 1: 28 | # will raise KeyError if either key doesn't exist 29 | return (i[kk], i[vk]) 30 | if isinstance(i, dict): 31 | return (list(i.keys())[0], list(i.values())[0]) 32 | else: 33 | raise TypeError() 34 | except Exception as exc: 35 | raise exc.__class__(i, exc) 36 | 37 | 38 | def _islist(i): 39 | assert isinstance(i, list) or isinstance(i, tuple), i 40 | 41 | 42 | def ordered(*iterables, **kwargs): 43 | """Merge iterables into an ordered dictionary and return them as a list of pairs 44 | 45 | Useful for merging lists of defaults that you want to keep in order 46 | 47 | Does not merge recursively (but that could be added from the built-in 48 | combine filter if necessary). 49 | 50 | Does not return an OrderedDict directly because Ansible doesn't support the 51 | data type and converts it in to its string representation. 52 | 53 | Elements of iterables are themselves an iterable, whose items can be: 54 | - two-item lists, where i[0] is the key and i[1] is the value 55 | - one-item dicts where the key is the key and the value is the value 56 | - dicts where i[k_key] is the key and i[v_key] is the value 57 | """ 58 | k_key = kwargs.get('k_key', 'key') 59 | v_key = kwargs.get('v_key', 'value') 60 | try_keys = partial(_try_keys, kk=k_key, vk=v_key) 61 | try: 62 | _islist(iterables) 63 | map(_islist, iterables) 64 | except AssertionError as exc: 65 | raise AnsibleError("|ordered expects lists, got " + repr(exc[0])) 66 | try: 67 | return list(OrderedDict(map(try_keys, chain(*iterables))).items()) 68 | except IndexError as exc: 69 | raise AnsibleError("|ordered must have 2 list elements %s: %s" % (exc[0], repr(exc[1]))) 70 | except KeyError as exc: 71 | raise AnsibleError("|ordered key not found in dict (hash) list element %s: %s" % (exc[0], repr(exc[1]))) 72 | except TypeError as exc: 73 | raise AnsibleError("|ordered list element must be list or dict, got " + repr(exc[0])) 74 | 75 | 76 | class FilterModule(object): 77 | def filters(self): 78 | return { 79 | 'subelement_union': subelement_union, 80 | 'ordered': ordered, 81 | } 82 | -------------------------------------------------------------------------------- /roles/ceph_mount/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install CephX Keys (kernel driver) 4 | ansible.builtin.copy: 5 | content: "{{ item.key }}" 6 | dest: "/etc/ceph/{{ item.name }}.secret" 7 | mode: 0400 8 | when: "(item.fstype | default('ceph')) == 'ceph'" 9 | loop: "{{ ceph_mounts }}" 10 | loop_control: 11 | label: "{{ item.name }}" 12 | 13 | - name: Install CephX Keys (FUSE driver) 14 | ansible.builtin.copy: 15 | content: | 16 | [client.{{ item.name }}] 17 | key = {{ item.key }} 18 | dest: "/etc/ceph/ceph.client.{{ item.name }}.keyring" 19 | mode: 0400 20 | when: "(item.fstype | default('ceph')) == 'fuse.ceph'" 21 | loop: "{{ ceph_mounts }}" 22 | loop_control: 23 | label: "{{ item.name }}" 24 | 25 | # WARNING: this only supports a single value for mon host, it wasn't apparent from the docs how to configure multiple 26 | # sets for multiple client instances/mounts, and is unnecessary for my purposes. 27 | # 28 | # client_dirsize_rbytes option due to meryl error "tar: read-db.meryl: file changed as we read it", references: 29 | # https://ceph-users.ceph.narkive.com/th0JxsKR/cephfs-tar-archiving-immediately-after-writing 30 | # https://www.spinics.net/lists/ceph-users/msg25010.html 31 | - name: Install ceph.conf (FUSE driver) 32 | ansible.builtin.copy: 33 | content: | 34 | [global] 35 | admin socket = /var/run/ceph/$cluster-$name-$pid.asok 36 | client reconnect stale = true 37 | client_dirsize_rbytes = false 38 | debug client = 0/2 39 | fuse big writes = true 40 | mon host = {{ ceph_mounts[0].src.rsplit(':', 1)[0] }} 41 | dest: /etc/ceph/ceph.conf 42 | mode: 0444 43 | 44 | - name: Create Ceph Mountpoints 45 | ansible.builtin.file: 46 | path: "{{ item.path }}" 47 | state: "directory" 48 | mode: 0755 49 | owner: "root" 50 | group: "root" 51 | loop: "{{ ceph_mounts }}" 52 | loop_control: 53 | label: "{{ item.name }}" 54 | 55 | - name: Mount Ceph Filesystems (kernel driver) 56 | ansible.builtin.mount: 57 | name: "{{ item.path }}" 58 | src: "{{ item.src }}" 59 | fstype: ceph 60 | passno: 2 61 | opts: "name={{ item.name }},secretfile=/etc/ceph/{{ item.name }}.secret{{ ',' ~ item.opts if item.opts else '' }}" 62 | state: "{{ ceph_mount_state }}" 63 | when: "(item.fstype | default('ceph')) == 'ceph'" 64 | loop: "{{ ceph_mounts }}" 65 | loop_control: 66 | label: "{{ item.name }} -> {{ item.path }}" 67 | 68 | - name: Mount Ceph Filesystems (FUSE driver) 69 | ansible.builtin.mount: 70 | name: "{{ item.path }}" 71 | src: "none" 72 | fstype: fuse.ceph 73 | passno: 2 74 | opts: "ceph.id={{ item.name }},ceph.conf=/etc/ceph/ceph.conf,ceph.client_mountpoint={{ item.src.rsplit(':', 1)[1] }},x-systemd.device-timeout=30,x-systemd.mount-timeout=30{{ ',' ~ item.opts if item.opts else '' }}" 75 | state: "{{ ceph_mount_state }}" 76 | when: "(item.fstype | default('ceph')) == 'fuse.ceph'" 77 | loop: "{{ ceph_mounts }}" 78 | loop_control: 79 | label: "{{ item.name }} -> {{ item.path }}" 80 | 81 | - name: Set Filesystem Permissions 82 | ansible.builtin.file: 83 | path: "{{ item.path }}" 84 | state: "directory" 85 | mode: "{{ item.mode | default('0755') }}" 86 | owner: "{{ item.owner | default('root') }}" 87 | group: "{{ item.group | default('root') }}" 88 | when: "ceph_mount_state == 'mounted'" 89 | loop: "{{ ceph_mounts }}" 90 | loop_control: 91 | label: "{{ item.name }}" 92 | -------------------------------------------------------------------------------- /roles/copy/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # TODO: Inspect lower priority lists (host_files > group_files > all_files) and 4 | # do not copy lower priority files if the same `dest` is present in a higher 5 | # priority list 6 | 7 | - name: Copy files 8 | copy: 9 | backup: "{{ item.backup | default(omit) }}" 10 | content: "{{ item.content | default(omit) }}" 11 | dest: "{{ item.dest }}" 12 | directory_mode: "{{ item.directory_mode | default(omit) }}" 13 | follow: "{{ item.follow | default(omit) }}" 14 | force: "{{ item.force | default(omit) }}" 15 | group: "{{ item.group | default(omit) }}" 16 | mode: "{{ item.mode | default(omit) }}" 17 | owner: "{{ item.owner | default(omit) }}" 18 | src: "{{ item.src | default(omit) }}" 19 | validate: "{{ item.validate | default(omit) }}" 20 | with_galaxyproject.general.inheritance_chain: "files" 21 | register: __files_result 22 | when: "item.state is not defined or item.state == 'present'" 23 | 24 | - name: Remove copy files with state=absent 25 | file: 26 | path: "{{ item.dest }}" 27 | state: absent 28 | with_galaxyproject.general.inheritance_chain: "files" 29 | when: "item.state is defined and item.state == 'absent'" 30 | 31 | - name: Copy templates 32 | template: 33 | backup: "{{ item.backup | default(omit) }}" 34 | dest: "{{ item.dest }}" 35 | follow: "{{ item.follow | default(omit) }}" 36 | force: "{{ item.force | default(omit) }}" 37 | group: "{{ item.group | default(omit) }}" 38 | mode: "{{ item.mode | default(omit) }}" 39 | owner: "{{ item.owner | default(omit) }}" 40 | src: "{{ item.src | default(omit) }}" 41 | validate: "{{ item.validate | default(omit) }}" 42 | register: __templates_result 43 | with_galaxyproject.general.inheritance_chain: "templates" 44 | 45 | - name: Remove template files with state=absent 46 | file: 47 | path: "{{ item.dest }}" 48 | state: absent 49 | with_galaxyproject.general.inheritance_chain: "templates" 50 | register: __templates_absent_result 51 | when: "item.state is defined and item.state == 'absent'" 52 | 53 | - name: Set lines in files 54 | lineinfile: 55 | attributes: "{{ item.attributes | default(omit) }}" 56 | backrefs: "{{ item.backrefs | default(omit) }}" 57 | backup: "{{ item.backup | default(omit) }}" 58 | create: "{{ item.create | default(omit) }}" 59 | firstmatch: "{{ item.firstmatch | default(omit) }}" 60 | group: "{{ item.group | default(omit) }}" 61 | insertafter: "{{ item.insertafter | default(omit) }}" 62 | insertbefore: "{{ item.insertbefore | default(omit) }}" 63 | line: "{{ item.line | default(omit) }}" 64 | mode: "{{ item.mode | default(omit) }}" 65 | owner: "{{ item.owner | default(omit) }}" 66 | path: "{{ item.path | default(item.dest) }}" 67 | regexp: "{{ item.regexp | default(omit) }}" 68 | state: "{{ item.state | default(omit) }}" 69 | unsafe_writes: "{{ item.unsafe_writes | default(omit) }}" 70 | validate: "{{ item.validate | default(omit) }}" 71 | with_galaxyproject.general.inheritance_chain: "lines" 72 | register: __lines_result 73 | notify: "{{ item.notify | default([]) }}" 74 | 75 | - name: Reload systemd if any changes were to systemd units 76 | ansible.builtin.systemd: 77 | daemon_reload: true 78 | when: ((__files_result.results + __templates_result.results + __templates_absent_result.results) | selectattr("changed")) is any and ((__files_result.results + __templates_result.results + __templates_absent_result.results) | selectattr("item.dest", "match", "/etc/systemd/system/.*")) is any 79 | -------------------------------------------------------------------------------- /roles/openstack/tasks/spawn.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create data volume 4 | openstack.cloud.volume: 5 | cloud: "{{ os_cloud_id }}" 6 | display_name: "{{ item.name }}" 7 | size: "{{ item.size }}" 8 | delegate_to: localhost 9 | loop: "{{ os_volumes | default([]) }}" 10 | 11 | - name: Spawn new instance 12 | openstack.cloud.server: 13 | cloud: "{{ os_cloud_id }}" 14 | name: "{{ os_name | default(inventory_hostname) }}" 15 | image: "{{ os_image }}" 16 | flavor: "{{ os_flavor }}" 17 | key_name: "{{ os_key_name }}" 18 | nics: "{{ os_nics }}" 19 | security_groups: "{{ os_security_groups }}" 20 | auto_ip: "{{ os_auto_ip | default(omit) }}" 21 | floating_ips: "{{ os_floating_ips | default(omit) }}" 22 | meta: "group={{ group_names[0] }}" 23 | boot_from_volume: "{{ os_boot_from_volume | default(omit) }}" 24 | volume_size: "{{ os_volume_size | default(omit) }}" 25 | #volumes: "{{ os_volumes | default(omit) }}" 26 | #volumes: "{{ os_volumes }}" 27 | timeout: "{{ openstack_spawn_timeout | default(omit) }}" 28 | userdata: | 29 | #cloud-config 30 | package_upgrade: false 31 | delegate_to: localhost 32 | register: __spawn_result 33 | 34 | # As far as I can tell, the first time this runs (when the attachment is done) is the only way to discover the volume device 35 | - name: Attach volumes to instances 36 | openstack.cloud.server_volume: 37 | cloud: "{{ os_cloud_id }}" 38 | server: "{{ os_name | default(inventory_hostname) }}" 39 | volume: "{{ item.name }}" 40 | delegate_to: localhost 41 | loop: "{{ os_volumes | default([]) }}" 42 | register: __attach_result 43 | 44 | - name: Set volume device(s) fact 45 | ansible.builtin.set_fact: 46 | __os_volume_devices: "{{ __attach_result.results | selectattr('attachments', 'defined') | map(attribute='attachments') | flatten | map(attribute='device') | list }}" 47 | 48 | # Turns out you can't have overlapping host_vars files and dirs, so for this to work, the host_vars that are 49 | # being used to create this instance will need to already be in a dir (so this step is redundant) 50 | #- name: Create host_vars dir 51 | # file: 52 | # path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}" 53 | # state: directory 54 | # when: __os_volume_devices | length > 0 55 | # delegate_to: localhost 56 | 57 | # I tried: 58 | # fstype: {{ '"{{' }} mounts[{{ loop.index0 }}].fstype {{ '}}' }} 59 | # but this results in: recursive loop detected in template string: {{ filesystems[0].dev }} 60 | # even though the actual attributes themselves aren't circular 61 | - name: Write volume device(s) to host_vars 62 | ansible.builtin.copy: 63 | content: | 64 | --- 65 | ## This file is automatically generated by the openstack role 66 | filesystems: 67 | {% for volume_def, device in os_volumes | zip(__os_volume_devices) %} 68 | - dev: {{ device }} 69 | fstype: {{ os_volumes[loop.index0].fstype }} 70 | {% endfor %} 71 | dest: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/os_volume_devices.yml" 72 | when: __os_volume_devices | length > 0 73 | delegate_to: localhost 74 | 75 | - name: Update inventory with spawned instance IP 76 | ansible.builtin.set_fact: 77 | # access_ipv4 is blank on JS2 for some reason 78 | ansible_host: "{{ __spawn_result.server.access_ipv4 or (__spawn_result.server.addresses[os_nics[0]['net-name']] | selectattr('OS-EXT-IPS:type', '==', (((os_auto_ip is defined and os_auto_ip) or os_floating_ips is defined) | ternary('floating', 'fixed'))) | first ).addr }}" 79 | 80 | - name: Log IP addresses 81 | ansible.builtin.debug: 82 | var: ansible_host 83 | 84 | - name: Assert address 85 | ansible.builtin.assert: 86 | that: ansible_host is truthy 87 | fail_msg: "No IP address returned by openstack.cloud.server" 88 | 89 | - name: Wait for instance to become accessible 90 | ansible.builtin.wait_for_connection: 91 | timeout: "{{ openstack_wait_timeout }}" 92 | 93 | - name: Set authorized keys 94 | ansible.builtin.authorized_key: 95 | user: "{{ ansible_user }}" 96 | key: "{% for authorized in os_admin_users %}{{ ssh_public_keys[authorized] ~ '\n' }}{% endfor %}" 97 | exclusive: "{{ os_admin_users_exclusive | default(false) }}" 98 | when: os_admin_users is defined 99 | -------------------------------------------------------------------------------- /roles/ssl/tasks/gen-cert.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create cert directory 4 | file: 5 | path: "{{ ssl_cert_dir }}" 6 | state: directory 7 | 8 | - name: Generate key for cert '{{ ssl_cert.name }}' in CA '{{ ssl_cert.ca }}' 9 | command: openssl genrsa 4096 10 | register: ssl_key_out 11 | 12 | - name: Set private key facts 13 | set_fact: 14 | ssl_key: "{{ ssl_key_out.stdout }}" 15 | ssl_key_var_name: "{{ ssl_cert.ca }}{{ '_' ~ inventory_hostname if ssl_cert.per_host is defined and ssl_cert.per_host else '' }}_{{ ssl_cert.name }}" 16 | ssl_key_file_name: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}_privatekey.yml" 17 | 18 | - name: Create extfile 19 | template: 20 | src: extfile.cnf.j2 21 | dest: "{{ ssl_cert_dir }}/extfile_{{ ssl_cert.name }}.cnf" 22 | when: ssl_cert_def.ext is defined 23 | 24 | - name: Check for ca.srl 25 | stat: 26 | path: "{{ ssl_dir }}/ca.srl" 27 | register: ssl_ca_srl_out 28 | 29 | - name: Write private key 30 | copy: 31 | content: "{{ ssl_key }}" 32 | dest: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}_privatekey.pem" 33 | mode: "0400" 34 | 35 | - block: 36 | 37 | - name: Generate certificate request 38 | command: > 39 | openssl req -new -sha256 40 | -subj '/C={{ ssl_cert_def.dn.country }}/ST={{ ssl_cert_def.dn.state }}/L={{ ssl_cert_def.dn.locality }}/O={{ ssl_cert_def.dn.organization }}/OU={{ ssl_cert_def.dn.organizational_unit }}/CN={{ ssl_cert_def.dn.common_name }}' 41 | -key {{ ssl_cert_dir }}/{{ ssl_cert.name }}_privatekey.pem 42 | -out {{ ssl_cert_dir }}/{{ ssl_cert.name }}.csr 43 | args: 44 | creates: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}.csr" 45 | 46 | - name: Create vault password tempfile 47 | command: mktemp -t tmp.ansible_ssl_vaultpass_XXXXXXXXXX 48 | register: ssl_vaultpass_mktemp_out 49 | 50 | - name: Create CA key tempfile 51 | command: mktemp -t tmp.ansible_ssl_cakey_XXXXXXXXXX 52 | register: ssl_cakey_mktemp_out 53 | 54 | - block: 55 | 56 | - name: Write vault password 57 | copy: 58 | content: "{{ ssl_vault_pass }}" 59 | dest: "{{ ssl_vaultpass_mktemp_out.stdout }}" 60 | mode: "0600" 61 | 62 | - name: Unvault CA key 63 | command: ansible-vault decrypt --vault-password-file={{ ssl_vaultpass_mktemp_out.stdout }} --output={{ ssl_cakey_mktemp_out.stdout }} {{ ssl_dir }}/ca-key.pem 64 | 65 | - name: Sign certificate request 66 | command: > 67 | openssl x509 -req -days 365 -sha256 68 | -in {{ ssl_cert_dir }}/{{ ssl_cert.name }}.csr 69 | -CA {{ ssl_dir }}/ca.pem 70 | -CAkey {{ ssl_cakey_mktemp_out.stdout }} 71 | {{ '-CAcreateserial' if not ssl_ca_srl_out.stat.exists else '-CAserial ' ~ ssl_dir ~ '/ca.srl' }} 72 | -out {{ ssl_cert_dir }}/{{ ssl_cert.name }}.pem 73 | {{ '-extfile ' ~ ssl_cert_dir ~ '/extfile_' ~ ssl_cert.name ~ '.cnf' if ssl_cert_def.ext else '' }} 74 | args: 75 | creates: "{{ ssl_cert_dir }}/{{ ssl_cert.name }}.pem" 76 | 77 | - name: Write private key vars file 78 | copy: 79 | content: | 80 | --- 81 | {{ ssl_key_var_name }}: | 82 | {{ ssl_key | indent(width=2) }} 83 | dest: "{{ ssl_key_file_name }}" 84 | mode: "0600" 85 | 86 | - name: Vault key vars file 87 | command: ansible-vault encrypt --vault-password-file={{ ssl_vaultpass_mktemp_out.stdout }} {{ ssl_key_file_name }} 88 | 89 | rescue: 90 | 91 | - name: Remove certificate and key on failure 92 | file: 93 | path: "{{ item }}" 94 | state: absent 95 | with_items: 96 | - "{{ ssl_cert_dir }}/{{ ssl_cert.name }}.pem" 97 | - "{{ ssl_key_file_name }}" 98 | 99 | always: 100 | 101 | - name: Remove secret tempfiles 102 | file: 103 | path: "{{ item }}" 104 | state: absent 105 | with_items: 106 | - "{{ ssl_vaultpass_mktemp_out.stdout }}" 107 | - "{{ ssl_cakey_mktemp_out.stdout }}" 108 | 109 | always: 110 | 111 | - name: Remove temporary items 112 | file: 113 | path: "{{ ssl_cert_dir }}/{{ item }}" 114 | state: absent 115 | with_items: 116 | - "{{ ssl_cert.name }}_privatekey.pem" 117 | - "{{ ssl_cert.name }}.csr" 118 | - "extfile_{{ ssl_cert.name }}.cnf" 119 | -------------------------------------------------------------------------------- /roles/supervisor/templates/redhat.init.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## 3 | ## This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 4 | ## 5 | # 6 | # supervisord This scripts turns supervisord on 7 | # 8 | # Author: Mike McGrath (based off yumupdatesd) 9 | # Jason Koppe adjusted to read sysconfig, 10 | # use supervisord tools to start/stop, conditionally wait 11 | # for child processes to shutdown, and startup later 12 | # 13 | # chkconfig: 345 83 04 14 | # 15 | # description: supervisor is a process control utility. It has a web based 16 | # xmlrpc interface as well as a few other nifty features. 17 | # processname: supervisord 18 | # config: /etc/supervisord.conf 19 | # pidfile: /var/run/supervisord.pid 20 | # 21 | 22 | # source function library 23 | . /etc/rc.d/init.d/functions 24 | 25 | # source system settings 26 | #[ -e /etc/sysconfig/supervisord ] && . /etc/sysconfig/supervisord 27 | 28 | # /etc/sysconfig/supervisord included directly here 29 | OPTIONS="-c {{ supervisord_conf_path }}" 30 | PIDFILE=/var/run/supervisord.pid 31 | 32 | # unset this variable if you don't care to wait for child processes to shutdown before removing the /var/lock/subsys/supervisord lock 33 | WAIT_FOR_SUBPROCESSES=yes 34 | 35 | # remove this if you manage number of open files in some other fashion 36 | ulimit -n 96000 37 | 38 | PREFIX={{ supervisord_prefix }} 39 | 40 | RETVAL=0 41 | 42 | # functions stolen from Ubuntu init script 43 | running_pid() 44 | { 45 | # Check if a given process pid's cmdline matches a given name 46 | pid=$1 47 | name=$2 48 | [ -z "$pid" ] && return 1 49 | [ ! -d /proc/$pid ] && return 1 50 | (cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1 51 | return 0 52 | } 53 | 54 | running() 55 | { 56 | # Check if the process is running looking at /proc 57 | # (works for all users) 58 | 59 | # No pidfile, probably no daemon present 60 | [ ! -f "$PIDFILE" ] && return 1 61 | # Obtain the pid and check it against the binary name 62 | pid=`cat $PIDFILE` 63 | running_pid $pid $PREFIX/bin/supervisord || return 1 64 | return 0 65 | } 66 | 67 | start() { 68 | echo "Starting supervisord: " 69 | if running ; then 70 | echo "ALREADY STARTED" 71 | return 1 72 | fi 73 | 74 | # start supervisord with options from sysconfig (stuff like -c) 75 | $PREFIX/bin/supervisord $OPTIONS 76 | 77 | # show initial startup status 78 | $PREFIX/bin/supervisorctl $OPTIONS status 79 | 80 | # only create the subsyslock if we created the PIDFILE 81 | [ -e $PIDFILE ] && touch /var/lock/subsys/supervisord 82 | } 83 | 84 | stop() { 85 | echo -n "Stopping supervisord: " 86 | $PREFIX/bin/supervisorctl $OPTIONS shutdown 87 | if [ -n "$WAIT_FOR_SUBPROCESSES" ]; then 88 | echo "Waiting roughly 60 seconds for $PIDFILE to be removed after child processes exit" 89 | for sleep in 2 2 2 2 4 4 4 4 8 8 8 8 last; do 90 | if [ ! -e $PIDFILE ] ; then 91 | echo "Supervisord exited as expected in under $total_sleep seconds" 92 | break 93 | else 94 | if [[ $sleep -eq "last" ]] ; then 95 | echo "Supervisord still working on shutting down. We've waited roughly 60 seconds, we'll let it do its thing from here" 96 | return 1 97 | else 98 | sleep $sleep 99 | total_sleep=$(( $total_sleep + $sleep )) 100 | fi 101 | 102 | fi 103 | done 104 | fi 105 | 106 | # always remove the subsys. we might have waited a while, but just remove it at this point. 107 | rm -f /var/lock/subsys/supervisord 108 | } 109 | 110 | restart() { 111 | stop 112 | start 113 | } 114 | 115 | case "$1" in 116 | start) 117 | start 118 | RETVAL=$? 119 | ;; 120 | stop) 121 | stop 122 | RETVAL=$? 123 | ;; 124 | restart|force-reload) 125 | restart 126 | RETVAL=$? 127 | ;; 128 | reload) 129 | $PREFIX/bin/supervisorctl $OPTIONS reload 130 | RETVAL=$? 131 | ;; 132 | condrestart) 133 | [ -f /var/lock/subsys/supervisord ] && restart 134 | RETVAL=$? 135 | ;; 136 | status) 137 | if running ; then 138 | $PREFIX/bin/supervisorctl status 139 | RETVAL=$? 140 | else 141 | echo "supervisord not running" 142 | RETVAL=1 143 | fi 144 | ;; 145 | *) 146 | echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}" 147 | exit 1 148 | esac 149 | 150 | exit $RETVAL 151 | -------------------------------------------------------------------------------- /roles/supervisor/templates/debian.init.j2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ## 3 | ## This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 4 | ## 5 | ### BEGIN INIT INFO 6 | # Provides: supervisord 7 | # Required-Start: $local_fs $remote_fs $networking 8 | # Required-Stop: $local_fs $remote_fs $networking 9 | # Default-Start: 2 3 4 5 10 | # Default-Stop: 0 1 6 11 | # Short-Description: Starts supervisord - see http://supervisord.org 12 | # Description: Starts and stops supervisord as needed - see http://supervisord.org 13 | ### END INIT INFO 14 | 15 | # Author: Leonard Norrgard 16 | # Version 1.0-alpha 17 | # Based on the /etc/init.d/skeleton script in Debian. 18 | 19 | # Please note: This script is not yet well tested. What little testing 20 | # that actually was done was only on supervisor 2.2b1. 21 | 22 | # Do NOT "set -e" 23 | 24 | # PATH should only include /usr/* if it runs after the mountnfs.sh script 25 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 26 | DESC="Run a set of applications as daemons." 27 | NAME=supervisord 28 | DAEMON={{ supervisord_prefix }}/bin/$NAME # Supervisord is installed in /usr/bin by default, but /usr/sbin would make more sense. 29 | SUPERVISORCTL={{ supervisord_prefix }}/bin/supervisorctl 30 | PIDFILE=/var/run/$NAME.pid 31 | DAEMON_ARGS="--pidfile ${PIDFILE}" 32 | SCRIPTNAME=/etc/init.d/$NAME 33 | 34 | # Exit if the package is not installed 35 | [ -x "$DAEMON" ] || exit 0 36 | 37 | # Read configuration variable file if it is present 38 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 39 | 40 | # Load the VERBOSE setting and other rcS variables 41 | . /lib/init/vars.sh 42 | 43 | # Define LSB log_* functions. 44 | # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. 45 | . /lib/lsb/init-functions 46 | 47 | # 48 | # Function that starts the daemon/service 49 | # 50 | do_start() 51 | { 52 | # Return 53 | # 0 if daemon has been started 54 | # 1 if daemon was already running 55 | # 2 if daemon could not be started 56 | [ -e $PIDFILE ] && return 1 57 | 58 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 59 | $DAEMON_ARGS \ 60 | || return 2 61 | # Add code here, if necessary, that waits for the process to be ready 62 | # to handle requests from services started subsequently which depend 63 | # on this one. As a last resort, sleep for some time. 64 | } 65 | 66 | # 67 | # Function that stops the daemon/service 68 | # 69 | do_stop() 70 | { 71 | # Return 72 | # 0 if daemon has been stopped 73 | # 1 if daemon was already stopped 74 | # 2 if daemon could not be stopped 75 | # other if a failure occurred 76 | [ -e $PIDFILE ] || return 1 77 | 78 | # Stop all processes under supervisord control. 79 | $SUPERVISORCTL stop all 80 | 81 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 82 | RETVAL="$?" 83 | [ "$RETVAL" = 2 ] && return 2 84 | # Wait for children to finish too if this is a daemon that forks 85 | # and if the daemon is only ever run from this initscript. 86 | # If the above conditions are not satisfied then add some other code 87 | # that waits for the process to drop all resources that could be 88 | # needed by services started subsequently. A last resort is to 89 | # sleep for some time. 90 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 91 | [ "$?" = 2 ] && return 2 92 | # Many daemons don't delete their pidfiles when they exit. 93 | rm -f $PIDFILE 94 | return "$RETVAL" 95 | } 96 | 97 | # 98 | # Function that sends a SIGHUP to the daemon/service 99 | # 100 | do_reload() { 101 | # 102 | # If the daemon can reload its configuration without 103 | # restarting (for example, when it is sent a SIGHUP), 104 | # then implement that here. 105 | # 106 | start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME 107 | return 0 108 | } 109 | 110 | case "$1" in 111 | start) 112 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 113 | do_start 114 | case "$?" in 115 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 116 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 117 | esac 118 | ;; 119 | stop) 120 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 121 | do_stop 122 | case "$?" in 123 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 124 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 125 | esac 126 | ;; 127 | #reload|force-reload) 128 | # 129 | # If do_reload() is not implemented then leave this commented out 130 | # and leave 'force-reload' as an alias for 'restart'. 131 | # 132 | #log_daemon_msg "Reloading $DESC" "$NAME" 133 | #do_reload 134 | #log_end_msg $? 135 | #;; 136 | restart|force-reload) 137 | # 138 | # If the "reload" option is implemented then remove the 139 | # 'force-reload' alias 140 | # 141 | log_daemon_msg "Restarting $DESC" "$NAME" 142 | do_stop 143 | case "$?" in 144 | 0|1) 145 | do_start 146 | case "$?" in 147 | 0) log_end_msg 0 ;; 148 | 1) log_end_msg 1 ;; # Old process is still running 149 | *) log_end_msg 1 ;; # Failed to start 150 | esac 151 | ;; 152 | *) 153 | # Failed to stop 154 | log_end_msg 1 155 | ;; 156 | esac 157 | ;; 158 | *) 159 | #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 160 | echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 161 | exit 3 162 | ;; 163 | esac 164 | 165 | : 166 | -------------------------------------------------------------------------------- /roles/supervisor/templates/ubuntu.init.j2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ## 3 | ## This file is maintained by Ansible - CHANGES WILL BE OVERWRITTEN 4 | ## 5 | # 6 | # Downloaded from: 7 | # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/supervisor/trusty/view/head:/debian/supervisor.init 8 | # 9 | # skeleton example file to build /etc/init.d/ scripts. 10 | # This file should be used to construct scripts for /etc/init.d. 11 | # 12 | # Written by Miquel van Smoorenburg . 13 | # Modified for Debian 14 | # by Ian Murdock . 15 | # Further changes by Javier Fernandez-Sanguino 16 | # 17 | # Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl 18 | # 19 | ### BEGIN INIT INFO 20 | # Provides: supervisor 21 | # Required-Start: $remote_fs $network $named 22 | # Required-Stop: $remote_fs $network $named 23 | # Default-Start: 2 3 4 5 24 | # Default-Stop: 0 1 6 25 | # Short-Description: Start/stop supervisor 26 | # Description: Start/stop supervisor daemon and its configured 27 | # subprocesses. 28 | ### END INIT INFO 29 | 30 | . /lib/lsb/init-functions 31 | 32 | PATH=/sbin:/bin:/usr/sbin:/usr/bin 33 | DAEMON={{ supervisord_prefix }}/bin/supervisord 34 | NAME=supervisord 35 | DESC=supervisor 36 | 37 | test -x $DAEMON || exit 0 38 | 39 | LOGDIR=/var/log/supervisor 40 | PIDFILE=/var/run/$NAME.pid 41 | DODTIME=5 # Time to wait for the server to die, in seconds 42 | # If this value is set too low you might not 43 | # let some servers to die gracefully and 44 | # 'restart' will not work 45 | 46 | # Include supervisor defaults if available 47 | if [ -f /etc/default/supervisor ] ; then 48 | . /etc/default/supervisor 49 | fi 50 | DAEMON_OPTS="-c {{ supervisord_conf_path }} $DAEMON_OPTS" 51 | 52 | set -e 53 | 54 | running_pid() 55 | { 56 | # Check if a given process pid's cmdline matches a given name 57 | pid=$1 58 | name=$2 59 | [ -z "$pid" ] && return 1 60 | [ ! -d /proc/$pid ] && return 1 61 | (cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1 62 | return 0 63 | } 64 | 65 | running() 66 | { 67 | # Check if the process is running looking at /proc 68 | # (works for all users) 69 | 70 | # No pidfile, probably no daemon present 71 | [ ! -f "$PIDFILE" ] && return 1 72 | # Obtain the pid and check it against the binary name 73 | pid=`cat $PIDFILE` 74 | running_pid $pid $DAEMON || return 1 75 | return 0 76 | } 77 | 78 | force_stop() { 79 | # Forcefully kill the process 80 | [ ! -f "$PIDFILE" ] && return 81 | if running ; then 82 | kill -15 $pid 83 | # Is it really dead? 84 | [ -n "$DODTIME" ] && sleep "$DODTIME"s 85 | if running ; then 86 | kill -9 $pid 87 | [ -n "$DODTIME" ] && sleep "$DODTIME"s 88 | if running ; then 89 | echo "Cannot kill $LABEL (pid=$pid)!" 90 | exit 1 91 | fi 92 | fi 93 | fi 94 | rm -f $PIDFILE 95 | return 0 96 | } 97 | 98 | case "$1" in 99 | start) 100 | echo -n "Starting $DESC: " 101 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 102 | --startas $DAEMON -- $DAEMON_OPTS 103 | test -f $PIDFILE || sleep 1 104 | if running ; then 105 | echo "$NAME." 106 | else 107 | echo " ERROR." 108 | fi 109 | ;; 110 | stop) 111 | echo -n "Stopping $DESC: " 112 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 113 | echo "$NAME." 114 | ;; 115 | force-stop) 116 | echo -n "Forcefully stopping $DESC: " 117 | force_stop 118 | if ! running ; then 119 | echo "$NAME." 120 | else 121 | echo " ERROR." 122 | fi 123 | ;; 124 | #reload) 125 | # 126 | # If the daemon can reload its config files on the fly 127 | # for example by sending it SIGHUP, do it here. 128 | # 129 | # If the daemon responds to changes in its config file 130 | # directly anyway, make this a do-nothing entry. 131 | # 132 | # echo "Reloading $DESC configuration files." 133 | # start-stop-daemon --stop --signal 1 --quiet --pidfile \ 134 | # /var/run/$NAME.pid --exec $DAEMON 135 | #;; 136 | force-reload) 137 | # 138 | # If the "reload" option is implemented, move the "force-reload" 139 | # option to the "reload" entry above. If not, "force-reload" is 140 | # just the same as "restart" except that it does nothing if the 141 | # daemon isn't already running. 142 | # check wether $DAEMON is running. If so, restart 143 | start-stop-daemon --stop --test --quiet --pidfile $PIDFILE \ 144 | --startas $DAEMON \ 145 | && $0 restart \ 146 | || exit 0 147 | ;; 148 | restart) 149 | echo -n "Restarting $DESC: " 150 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 151 | [ -n "$DODTIME" ] && sleep $DODTIME 152 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 153 | --startas $DAEMON -- $DAEMON_OPTS 154 | echo "$NAME." 155 | ;; 156 | status) 157 | echo -n "$LABEL is " 158 | if running ; then 159 | echo "running" 160 | else 161 | echo " not running." 162 | exit 1 163 | fi 164 | ;; 165 | *) 166 | N=/etc/init.d/$NAME 167 | # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 168 | echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 169 | exit 1 170 | ;; 171 | esac 172 | 173 | exit 0 174 | -------------------------------------------------------------------------------- /roles/paths/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create filesystems 4 | community.general.filesystem: 5 | dev: "{{ item.dev }}" 6 | force: "{{ item.force | default(omit) }}" 7 | fstype: "{{ item.fstype }}" 8 | opts: "{{ item.opts | default(omit) }}" 9 | resizefs: "{{ item.resizefs | default(omit) }}" 10 | loop: "{{ filesystems | default([]) }}" 11 | 12 | - name: Create mountpoints 13 | ansible.builtin.file: 14 | path: "{{ item.path | default(item.name) }}" 15 | state: "directory" 16 | owner: "{{ item.owner | default(omit) }}" 17 | group: "{{ item.group | default(omit) }}" 18 | mode: "{{ item.mode | default(omit) }}" 19 | with_galaxyproject.general.inheritance_chain: "mounts" 20 | 21 | - name: Mount filesystems 22 | ansible.posix.mount: 23 | name: "{{ item.path | default(item.name) }}" 24 | src: "{{ item.src }}" 25 | fstype: "{{ item.fstype }}" 26 | opts: "{{ item.opts | default(omit) }}" 27 | state: "mounted" 28 | with_galaxyproject.general.inheritance_chain: "mounts" 29 | 30 | - name: Set mountpoint permissions 31 | ansible.builtin.file: 32 | path: "{{ item.path | default(item.name) }}" 33 | state: "directory" 34 | owner: "{{ item.owner | default(omit) }}" 35 | group: "{{ item.group | default(omit) }}" 36 | mode: "{{ item.mode | default(omit) }}" 37 | with_galaxyproject.general.inheritance_chain: "mounts" 38 | 39 | - name: Include ZFS install tasks 40 | ansible.builtin.include_tasks: "install_zfs_{{ ansible_os_family | lower }}.yml" 41 | when: "ansible_system == 'Linux' and lookup('galaxyproject.general.inheritance_chain', 'zfs_filesystems') is truthy" 42 | 43 | - name: Create ZFS zpools 44 | community.general.zpool: 45 | altroot: "{{ item.altroot | default(omit) }}" 46 | disable_new_features: "{{ item.disable_new_features | default(omit) }}" 47 | filesystem_properties: "{{ item.filesystem_properties | default(omit) }}" 48 | force: "{{ item.force | default(omit) }}" 49 | mountpoint: "{{ item.mountpoint | default(omit) }}" 50 | name: "{{ item.name }}" 51 | pool_properties: "{{ item.pool_properties | default(omit) }}" 52 | state: "{{ item.state | default(omit) }}" 53 | temp_name: "{{ item.temp_name | default(omit) }}" 54 | vdevs: "{{ item.vdevs }}" 55 | loop: "{{ zfs_zpools | default([]) }}" 56 | 57 | - name: Create ZFS filesystems 58 | community.general.zfs: 59 | name: "{{ item.name }}" 60 | state: "{{ item.state | default('present') }}" 61 | extra_zfs_properties: 62 | aclinherit: "{{ item.aclinherit | default(omit) }}" 63 | aclmode: "{{ item.aclmode | default(omit) }}" 64 | atime: "{{ item.atime | default(omit) }}" 65 | canmount: "{{ item.canmount | default(omit) }}" 66 | casesensitivity: "{{ item.casesensitivity | default(omit) }}" 67 | checksum: "{{ item.checksum | default(omit) }}" 68 | compression: "{{ item.compression | default(omit) }}" 69 | copies: "{{ item.copies | default(omit) }}" 70 | dedup: "{{ item.dedup | default(omit) }}" 71 | devices: "{{ item.devices | default(omit) }}" 72 | exec: "{{ item.exec | default(omit) }}" 73 | jailed: "{{ item.jailed | default(omit) }}" 74 | logbias: "{{ item.logbias | default(omit) }}" 75 | mountpoint: "{{ item.mountpoint | default(omit) }}" 76 | nbmand: "{{ item.nbmand | default(omit) }}" 77 | normalization: "{{ item.normalization | default(omit) }}" 78 | primarycache: "{{ item.primarycache | default(omit) }}" 79 | quota: "{{ item.quota | default(omit) }}" 80 | readonly: "{{ item.readonly | default(omit) }}" 81 | recordsize: "{{ item.recordsize | default(omit) }}" 82 | refquota: "{{ item.refquota | default(omit) }}" 83 | refreservation: "{{ item.refreservation | default(omit) }}" 84 | reservation: "{{ item.reservation | default(omit) }}" 85 | secondarycache: "{{ item.secondarycache | default(omit) }}" 86 | setuid: "{{ item.setuid | default(omit) }}" 87 | shareiscsi: "{{ item.shareiscsi | default(omit) }}" 88 | sharenfs: "{{ item.sharenfs | default(omit) }}" 89 | snapdir: "{{ item.snapdir | default(omit) }}" 90 | sync: "{{ item.sync | default(omit) }}" 91 | utf8only: "{{ item.utf8only | default(omit) }}" 92 | volblocksize: "{{ item.volblocksize | default(omit) }}" 93 | volsize: "{{ item.volsize | default(omit) }}" 94 | vscan: "{{ item.vscan | default(omit) }}" 95 | xattr: "{{ item.xattr | default(omit) }}" 96 | zoned: "{{ item.zoned | default(omit) }}" 97 | loop: "{{ zfs_filesystems | default([]) }}" 98 | environment: 99 | PATH: /native/sbin:{{ ansible_env.PATH }} 100 | 101 | - name: Set ZFS mountpoint permissions 102 | ansible.builtin.file: 103 | path: "{{ item.mountpoint | default('/' + item.name ) }}" 104 | state: "directory" 105 | owner: "{{ item.owner | default('root') }}" 106 | group: "{{ item.group | default('root') }}" 107 | mode: "{{ item.mode | default('0755') }}" 108 | loop: "{{ zfs_filesystems | default([]) }}" 109 | when: item.mountpoint is not defined or item.mountpoint.startswith('/') 110 | 111 | - name: Set ZFS administrative permissions 112 | community.general.zfs_delegate_admin: 113 | name: "{{ item.name }}" 114 | state: "{{ item.state | default('present') }}" 115 | users: "{{ item.users | default(omit) }}" 116 | groups: "{{ item.groups | default(omit) }}" 117 | permissions: "{{ item.permissions | default(omit) }}" 118 | loop: "{{ zfs_admin_permissions | default([]) }}" 119 | 120 | - name: Create btrfs subvolumes 121 | community.general.btrfs_subvolume: 122 | automount: "{{ item.automount | default(omit) }}" 123 | default: "{{ item.default | default(omit) }}" 124 | filesystem_device: "{{ item.filesystem_device | default(omit) }}" 125 | filesystem_label: "{{ item.filesystem_label | default(omit) }}" 126 | filesystem_uuid: "{{ item.filesystem_uuid | default(omit) }}" 127 | name: "{{ item.name | default(item.path) }}" 128 | recursive: "{{ item.recursive | default(omit) }}" 129 | snapshot_conflict: "{{ item.snapshot_conflict | default(omit) }}" 130 | snapshot_source: "{{ item.snapshot_source | default(omit) }}" 131 | state: "{{ item.state | default(omit) }}" 132 | with_galaxyproject.general.inheritance_chain: "btrfs_subvolumes" 133 | 134 | - name: Create directories 135 | ansible.builtin.file: 136 | path: "{{ item.path }}" 137 | owner: "{{ item.owner | default(omit) }}" 138 | group: "{{ item.group | default(omit) }}" 139 | recurse: "{{ item.recurse | default(omit) }}" 140 | mode: "{{ item.mode | default(omit) }}" 141 | state: "directory" 142 | with_galaxyproject.general.inheritance_chain: "directories" 143 | 144 | - name: Create links 145 | ansible.builtin.file: 146 | path: "{{ item.path }}" 147 | src: "{{ item.src }}" 148 | owner: "{{ item.owner | default(omit) }}" 149 | group: "{{ item.group | default(omit) }}" 150 | mode: "{{ item.mode | default(omit) }}" 151 | force: "{{ item.force | default(omit) }}" 152 | state: "link" 153 | with_galaxyproject.general.inheritance_chain: "links" 154 | -------------------------------------------------------------------------------- /roles/packages/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Update cache and ensure apt-transport-https is installed 4 | ansible.builtin.apt: 5 | pkg: apt-transport-https 6 | update_cache: yes 7 | cache_valid_time: 3600 8 | when: ansible_os_family == "Debian" 9 | 10 | - name: Add APT keys (apt-key) 11 | ansible.builtin.apt_key: 12 | data: "{{ item.data | default(omit) }}" 13 | file: "{{ item.file | default(omit) }}" 14 | id: "{{ item.id | default(omit) }}" 15 | keyring: "{{ item.keyring | default(omit) }}" 16 | keyserver: "{{ item.keyserver | default(omit) }}" 17 | state: "{{ item.state | default(omit) }}" 18 | url: "{{ item.url | default(omit) }}" 19 | validate_certs: "{{ item.validate_certs | default(omit) }}" 20 | with_galaxyproject.general.inheritance_chain: "apt_keys" 21 | when: 22 | - ansible_os_family == "Debian" 23 | - ansible_distribution == "Debian" 24 | - ansible_distribution_major_version < "12" 25 | 26 | - name: Add APT keys (URL) 27 | ansible.builtin.get_url: 28 | url: "{{ item.url }}" 29 | dest: "{{ item.dest }}" 30 | checksum: "{{ item.checksum | default(omit) }}" 31 | mode: "{{ item.mode | default('0644') }}" 32 | with_galaxyproject.general.inheritance_chain: "apt_keys" 33 | when: 34 | - ansible_os_family == "Debian" 35 | - ansible_distribution == "Debian" 36 | - ansible_distribution_major_version >= "12" 37 | - item.url is defined 38 | 39 | - name: Add APT keys (copy) 40 | ansible.builtin.copy: 41 | content: "{{ item.content | default(omit) }}" 42 | src: "{{ item.src | default(omit) }}" 43 | dest: "{{ item.dest }}" 44 | mode: "{{ item.mode | default('0644') }}" 45 | with_galaxyproject.general.inheritance_chain: "apt_keys" 46 | when: 47 | - ansible_os_family == "Debian" 48 | - ansible_distribution == "Debian" 49 | - ansible_distribution_major_version >= "12" 50 | - item.url is not defined 51 | 52 | - name: Add APT repositories 53 | apt_repository: 54 | mode: "{{ item.mode | default(omit) }}" 55 | repo: "{{ item.repo }}" 56 | state: "{{ item.state | default(omit) }}" 57 | update_cache: "{{ item.update_cache | default(omit) }}" 58 | validate_certs: "{{ item.validate_certs | default(omit) }}" 59 | with_galaxyproject.general.inheritance_chain: "apt_repositories" 60 | when: ansible_os_family == "Debian" 61 | register: apt_repository 62 | 63 | # NOTE: RPM signing keys are different than YUM signing keys (which go in gpgkey in yum_repository) 64 | - name: Add RPM keys 65 | rpm_key: 66 | key: "{{ item.key }}" 67 | fingerprint: "{{ item.fingerprint | default(omit) }}" 68 | state: "{{ item.state | default(omit) }}" 69 | validate_certs: "{{ item.validate_certs | default(omit) }}" 70 | with_galaxyproject.general.inheritance_chain: "rpm_keys" 71 | when: ansible_os_family == "RedHat" 72 | 73 | - name: Add YUM repositories 74 | yum_repository: 75 | name: "{{ item.name }}" 76 | description: "{{ item.description }}" 77 | state: present 78 | async: "{{ item.async | default(omit) }}" 79 | attributes: "{{ item.attributes | default(omit) }}" 80 | bandwidth: "{{ item.bandwidth | default(omit) }}" 81 | baseurl: "{{ item.baseurl | default(omit) }}" 82 | cost: "{{ item.cost | default(omit) }}" 83 | deltarpm_metadata_percentage: "{{ item.deltarpm_metadata_percentage | default(omit) }}" 84 | deltarpm_percentage: "{{ item.deltarpm_percentage | default(omit) }}" 85 | enabled: "{{ item.enabled | default(omit) }}" 86 | enablegroups: "{{ item.enablegroups | default(omit) }}" 87 | exclude: "{{ item.exclude | default(omit) }}" 88 | failovermethod: "{{ item.failovermethod | default(omit) }}" 89 | file: "{{ item.file | default(omit) }}" 90 | gpgcakey: "{{ item.gpgcakey | default(omit) }}" 91 | gpgcheck: "{{ item.gpgcheck | default(omit) }}" 92 | gpgkey: "{{ item.gpgkey | default(omit) }}" 93 | group: "{{ item.group | default(omit) }}" 94 | http_caching: "{{ item.http_caching | default(omit) }}" 95 | include: "{{ item.include | default(omit) }}" 96 | includepkgs: "{{ item.includepkgs | default(omit) }}" 97 | ip_resolve: "{{ item.ip_resolve | default(omit) }}" 98 | keepalive: "{{ item.keepalive | default(omit) }}" 99 | keepcache: "{{ item.keepcache | default(omit) }}" 100 | metadata_expire: "{{ item.metadata_expire | default(omit) }}" 101 | metadata_expire_filter: "{{ item.metadata_expire_filter | default(omit) }}" 102 | metalink: "{{ item.metalink | default(omit) }}" 103 | mirrorlist: "{{ item.mirrorlist | default(omit) }}" 104 | mirrorlist_expire: "{{ item.mirrorlist_expire | default(omit) }}" 105 | mode: "{{ item.mode | default(omit) }}" 106 | owner: "{{ item.owner | default(omit) }}" 107 | params: "{{ item.params | default(omit) }}" 108 | password: "{{ item.password | default(omit) }}" 109 | priority: "{{ item.priority | default(omit) }}" 110 | protect: "{{ item.protect | default(omit) }}" 111 | proxy: "{{ item.proxy | default(omit) }}" 112 | proxy_password: "{{ item.proxy_password | default(omit) }}" 113 | proxy_username: "{{ item.proxy_username | default(omit) }}" 114 | repo_gpgcheck: "{{ item.repo_gpgcheck | default(omit) }}" 115 | reposdir: "{{ item.reposdir | default(omit) }}" 116 | retries: "{{ item.retries | default(omit) }}" 117 | s3_enabled: "{{ item.s3_enabled | default(omit) }}" 118 | selevel: "{{ item.selevel | default(omit) }}" 119 | serole: "{{ item.serole | default(omit) }}" 120 | setype: "{{ item.setype | default(omit) }}" 121 | seuser: "{{ item.seuser | default(omit) }}" 122 | skip_if_unavailable: "{{ item.skip_if_unavailable | default(omit) }}" 123 | ssl_check_cert_permissions: "{{ item.ssl_check_cert_permissions | default(omit) }}" 124 | sslcacert: "{{ item.sslcacert | default(omit) }}" 125 | sslclientcert: "{{ item.sslclientcert | default(omit) }}" 126 | sslclientkey: "{{ item.sslclientkey | default(omit) }}" 127 | sslverify: "{{ item.sslverify | default(omit) }}" 128 | throttle: "{{ item.throttle | default(omit) }}" 129 | timeout: "{{ item.timeout | default(omit) }}" 130 | ui_repoid_vars: "{{ item.ui_repoid_vars | default(omit) }}" 131 | unsafe_writes: "{{ item.unsafe_writes | default(omit) }}" 132 | username: "{{ item.username | default(omit) }}" 133 | with_galaxyproject.general.inheritance_chain: "yum_repositories" 134 | when: item.state is undefined or item.state == 'present' 135 | register: _yum_repositories_results 136 | 137 | # This step is necessary to import YUM repo (note: NOT rpm) signing keys 138 | # https://github.com/ansible/ansible/issues/20711 139 | - name: Update cache and import keys for updated yum repos 140 | command: "yum -q makecache -y --disablerepo=* --enablerepo={{ item.item.name }}" 141 | with_items: "{{ _yum_repositories_results.results }}" 142 | when: item is changed 143 | 144 | - name: Remove YUM repositories 145 | file: 146 | path: "/etc/yum.repos.d/ansible-{{ item.name }}.repo" 147 | state: absent 148 | with_galaxyproject.general.inheritance_chain: "yum_repositories" 149 | when: item.state is defined and item.state == 'absent' 150 | 151 | - name: Update APT cache for repository addition 152 | apt: 153 | update_cache: true 154 | when: 155 | - ansible_os_family == "Debian" 156 | - apt_repository is changed 157 | 158 | - name: Update APT cache if out of date 159 | apt: 160 | update_cache: true 161 | cache_valid_time: "{{ packages_cache_valid_time | default(3600) }}" 162 | when: 163 | - ansible_os_family == "Debian" 164 | - (packages_apt_auto_update_cache | default(true)) is true 165 | 166 | - name: Install centos-release-scl 167 | yum: 168 | name: centos-release-scl 169 | when: 170 | - install_scl 171 | - ansible_os_family == "RedHat" 172 | - ansible_distribution_major_version < "8" 173 | 174 | - name: EPEL Block (EL7) 175 | block: 176 | 177 | - name: Install EPEL GPG Key 178 | ansible.builtin.rpm_key: 179 | key: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{{ ansible_distribution_major_version }}" 180 | 181 | - name: Install epel-release package 182 | ansible.builtin.package: 183 | name: "https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm" 184 | 185 | when: 186 | - install_epel 187 | - ansible_os_family == "RedHat" 188 | - ansible_distribution_major_version < "8" 189 | 190 | - name: EPEL Block (EL8+) 191 | block: 192 | 193 | - name: Enable PowerTools repo (EL8) 194 | community.general.ini_file: 195 | path: "/etc/yum.repos.d/{{ powertools_repo_file[ansible_distribution] }}" 196 | section: powertools 197 | option: enabled 198 | value: "1" 199 | mode: "0644" 200 | when: 201 | - ansible_distribution_major_version == "8" 202 | 203 | - name: Enable CRB repo (EL9) 204 | community.general.ini_file: 205 | path: "/etc/yum.repos.d/{{ crb_repo_file[ansible_distribution] }}" 206 | section: crb 207 | option: enabled 208 | value: "1" 209 | mode: "0644" 210 | when: 211 | - ansible_distribution_major_version == "9" 212 | 213 | - name: Install epel-release 214 | ansible.builtin.dnf: 215 | name: epel-release 216 | 217 | when: 218 | - install_epel 219 | - ansible_os_family == "RedHat" 220 | - ansible_distribution_major_version >= "8" 221 | 222 | - name: Install packages 223 | package: 224 | name: "{{ lookup('galaxyproject.general.inheritance_chain', 'packages') }}" 225 | when: not (ansible_distribution == "SmartOS" and ansible_container is not defined) 226 | -------------------------------------------------------------------------------- /roles/paths/library/zfs_delegate_admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # (c) 2015, Nate Coraor 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | # 21 | from __future__ import absolute_import 22 | __metaclass__ = type 23 | 24 | ANSIBLE_METADATA = {'status': ['preview'], 25 | 'supported_by': 'community', 26 | 'metadata_version': '1.1'} 27 | 28 | 29 | DOCUMENTATION = ''' 30 | --- 31 | module: zfs_delegate_admin 32 | short_description: Manage ZFS delegated administration (user admin privileges) 33 | description: 34 | - Manages ZFS file system delegated administration permissions, which allow unprivileged users to perform ZFS 35 | operations normally restricted to the superuser. 36 | - See the "zfs allow" section of C(zfs(1M)) for detailed explanations of options. This module attempts to adhere to 37 | the behavior of the command line tool as much as possible. 38 | requirements: 39 | - "A ZFS/OpenZFS implementation that supports delegation with `zfs allow`, including: Solaris >= 10, illumos (all 40 | versions), FreeBSD >= 8.0R, ZFS on Linux >= 0.7.0." 41 | version_added: "2.5" 42 | options: 43 | name: 44 | description: 45 | - File system or volume name e.g. C(rpool/myfs) 46 | required: true 47 | state: 48 | description: 49 | - Whether to allow (C(present)), or unallow (C(absent)) a permission. When set to C(present), at least one 50 | "entity" param of I(users), I(groups), or I(everyone) are required. When set to C(absent), removes permissions 51 | from the specified entities, or removes all permissions if no entity params are specified. 52 | required: true 53 | choices: [present, absent] 54 | users: 55 | description: 56 | - List of users to whom permission(s) should be granted 57 | groups: 58 | description: 59 | - List of groups to whom permission(s) should be granted 60 | everyone: 61 | description: 62 | - Apply permissions to everyone. 63 | default: false 64 | type: bool 65 | permissions: 66 | description: 67 | - The list of permission(s) to delegate (required if C(state) is C(present)) 68 | choices: ['allow','clone','create','destroy',...] 69 | local: 70 | description: 71 | - Apply permissions to C(name) locally (C(zfs allow -l)) 72 | default: null 73 | type: bool 74 | descendents: 75 | description: 76 | - Apply permissions to C(name)'s descendents (C(zfs allow -d)) 77 | default: null 78 | type: bool 79 | recursive: 80 | description: 81 | - Unallow permissions recursively (ignored when C(state) is C(present)) 82 | default: false 83 | type: bool 84 | author: "Nate Coraor (@natefoo)" 85 | ''' 86 | 87 | EXAMPLES = ''' 88 | # Grant `zfs allow` and `unallow` permission to the `adm` user with the default local+descendents scope 89 | - zfs_delegate_admin: name=rpool/myfs users=adm permissions=allow,unallow 90 | 91 | # Grant `zfs send` to everyone, plus the group `backup` 92 | - zfs_delegate_admin: name=rpool/myvol groups=backup everyone=yes permissions=send 93 | 94 | # Grant `zfs send,receive` to users `foo` and `bar` with local scope only 95 | - zfs_delegate_admin: name=rpool/myfs users=foo,bar permissions=send,receive local=yes 96 | 97 | # Revoke all permissions from everyone (permissions specifically assigned to users and groups remain) 98 | - zfs_delegate_admin: name=rpool/myfs state=absent everyone=yes 99 | ''' 100 | 101 | # This module does not return anything other than the standard 102 | # changed/state/msg/stdout 103 | RETURN = ''' 104 | ''' 105 | 106 | from itertools import product 107 | 108 | from ansible.module_utils.basic import AnsibleModule 109 | 110 | 111 | class ZfsDelegateAdmin(object): 112 | def __init__(self, module): 113 | self.module = module 114 | self.name = module.params.get('name') 115 | self.state = module.params.get('state') 116 | self.users = module.params.get('users') 117 | self.groups = module.params.get('groups') 118 | self.everyone = module.params.get('everyone') 119 | self.perms = module.params.get('permissions') 120 | self.scope = None 121 | self.changed = False 122 | self.initial_perms = None 123 | self.subcommand = 'allow' 124 | self.recursive_opt = [] 125 | self.run_method = self.update 126 | 127 | self.setup(module) 128 | 129 | def setup(self, module): 130 | """ Validate params and set up for run. 131 | """ 132 | if self.state == 'absent': 133 | self.subcommand = 'unallow' 134 | if module.params.get('recursive'): 135 | self.recursive_opt = ['-r'] 136 | 137 | local = module.params.get('local') 138 | descendents = module.params.get('descendents') 139 | if (local and descendents) or (not local and not descendents): 140 | self.scope = 'ld' 141 | elif local: 142 | self.scope = 'l' 143 | elif descendents: 144 | self.scope = 'd' 145 | else: 146 | self.module.fail_json(msg='Impossible value for local and descendents') 147 | 148 | if not (self.users or self.groups or self.everyone): 149 | if self.state == 'present': 150 | self.module.fail_json(msg='One of `users`, `groups`, or `everyone` must be set') 151 | elif self.state == 'absent': 152 | self.run_method = self.clear 153 | # ansible ensures the else cannot happen here 154 | 155 | self.zfs_path = module.get_bin_path('zfs', True) 156 | 157 | @property 158 | def current_perms(self): 159 | """ Parse the output of `zfs allow ` to retrieve current permissions. 160 | """ 161 | out = self.run_zfs_raw(subcommand='allow') 162 | perms = { 163 | 'l': {'u': {}, 'g': {}, 'e': []}, 164 | 'd': {'u': {}, 'g': {}, 'e': []}, 165 | 'ld': {'u': {}, 'g': {}, 'e': []}, 166 | } 167 | linemap = { 168 | 'Local permissions:': 'l', 169 | 'Descendent permissions:': 'd', 170 | 'Local+Descendent permissions:': 'ld', 171 | } 172 | scope = None 173 | for line in out.splitlines(): 174 | scope = linemap.get(line, scope) 175 | if not scope: 176 | continue 177 | try: 178 | if line.startswith('\tuser ') or line.startswith('\tgroup '): 179 | ent_type, ent, cur_perms = line.split() 180 | perms[scope][ent_type[0]][ent] = cur_perms.split(',') 181 | elif line.startswith('\teveryone '): 182 | perms[scope]['e'] = line.split()[1].split(',') 183 | except ValueError: 184 | self.module.fail_json(msg="Cannot parse user/group permission output by `zfs allow`: '%s'" % line) 185 | return perms 186 | 187 | def run_zfs_raw(self, subcommand=None, args=None): 188 | """ Run a raw zfs command, fail on error. 189 | """ 190 | cmd = [self.zfs_path, subcommand or self.subcommand] + (args or []) + [self.name] 191 | rc, out, err = self.module.run_command(cmd) 192 | if rc: 193 | self.module.fail_json(msg='Command `%s` failed: %s' % (' '.join(cmd), err)) 194 | return out 195 | 196 | def run_zfs(self, args): 197 | """ Run zfs allow/unallow with appropriate options as per module arguments. 198 | """ 199 | args = self.recursive_opt + ['-' + self.scope] + args 200 | if self.perms: 201 | args.append(','.join(self.perms)) 202 | return self.run_zfs_raw(args=args) 203 | 204 | def clear(self): 205 | """ Called by run() to clear all permissions. 206 | """ 207 | changed = False 208 | stdout = '' 209 | for scope, ent_type in product(('ld', 'l', 'd'), ('u', 'g')): 210 | for ent in self.initial_perms[scope][ent_type].keys(): 211 | stdout += self.run_zfs(['-%s' % ent_type, ent]) 212 | changed = True 213 | for scope in ('ld', 'l', 'd'): 214 | if self.initial_perms[scope]['e']: 215 | stdout += self.run_zfs(['-e']) 216 | changed = True 217 | return (changed, stdout) 218 | 219 | def update(self): 220 | """ Update permissions as per module arguments. 221 | """ 222 | stdout = '' 223 | for ent_type, entities in (('u', self.users), ('g', self.groups)): 224 | if entities: 225 | stdout += self.run_zfs(['-%s' % ent_type, ','.join(entities)]) 226 | if self.everyone: 227 | stdout += self.run_zfs(['-e']) 228 | return (self.initial_perms != self.current_perms, stdout) 229 | 230 | def run(self): 231 | """ Run an operation, return results for Ansible. 232 | """ 233 | exit_args = {'state': self.state} 234 | self.initial_perms = self.current_perms 235 | exit_args['changed'], stdout = self.run_method() 236 | if exit_args['changed']: 237 | exit_args['msg'] = 'ZFS delegated admin permissions updated' 238 | exit_args['stdout'] = stdout 239 | self.module.exit_json(**exit_args) 240 | 241 | 242 | def main(): 243 | module = AnsibleModule( 244 | argument_spec=dict( 245 | name=dict(required=True), 246 | state=dict(default='present', choices=['absent', 'present']), 247 | users=dict(default=[], type='list'), 248 | groups=dict(default=[], type='list'), 249 | everyone=dict(default=False, type='bool'), 250 | permissions=dict(default=[], type='list'), 251 | local=dict(default=None, type='bool'), 252 | descendents=dict(default=None, type='bool'), 253 | recursive=dict(default=False, type='bool') 254 | ), 255 | supports_check_mode=False, 256 | required_if=[('state', 'present', ['permissions'])] 257 | ) 258 | zfs_delegate_admin = ZfsDelegateAdmin(module) 259 | zfs_delegate_admin.run() 260 | 261 | 262 | if __name__ == '__main__': 263 | main() 264 | --------------------------------------------------------------------------------