From 51ff83de30db6934e243226ce05c6394b8986a12 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Wed, 6 Feb 2019 14:53:10 +1100 Subject: Add Ansible playbook for node configuration This will replace all of the existing node provisioning/configuration. CentOS 7 nodes are currently supported. Signed-off-by: Martin Schwenke --- ansible/node/ad.yml | 7 ++ ansible/node/base.yml | 6 + ansible/node/build.yml | 8 ++ ansible/node/cbuild.yml | 8 ++ ansible/node/nas.yml | 11 ++ ansible/node/roles/README | 33 +++++ .../node/roles/ad/tasks/generic/configure_ad.yml | 65 ++++++++++ ansible/node/roles/ad/tasks/main.yml | 12 ++ ansible/node/roles/ad/tasks/redhat/packages.yml | 22 ++++ ansible/node/roles/build/tasks/main.yml | 7 ++ ansible/node/roles/build/tasks/redhat/packages.yml | 24 ++++ .../roles/build/tasks/redhat/packaging_setup.yml | 8 ++ .../roles/clusterfs/files/autocluster-gpfs.profile | 2 + ansible/node/roles/clusterfs/tasks/main.yml | 7 ++ .../clusterfs/tasks/redhat/clusterfs-gpfs.yml | 20 +++ ansible/node/roles/clusterfs/tasks/redhat/repo.yml | 12 ++ ansible/node/roles/common/files/rsyslog.conf | 14 +++ ansible/node/roles/common/files/ssh_config | 2 + ansible/node/roles/common/handlers/main.yml | 12 ++ .../roles/common/tasks/generic/autocluster.yml | 5 + ansible/node/roles/common/tasks/generic/hosts.yml | 5 + .../node/roles/common/tasks/generic/mount_home.yml | 12 ++ .../roles/common/tasks/generic/resolv_conf.yml | 5 + .../node/roles/common/tasks/generic/rsyslog.yml | 7 ++ .../node/roles/common/tasks/generic/selinux.yml | 4 + ansible/node/roles/common/tasks/generic/ssh.yml | 5 + .../node/roles/common/tasks/generic/timezone.yml | 12 ++ ansible/node/roles/common/tasks/main.yml | 25 ++++ .../node/roles/common/tasks/redhat/firewall.yml | 6 + ansible/node/roles/common/tasks/redhat/ntp.yml | 18 +++ .../node/roles/common/tasks/redhat/packages.yml | 53 ++++++++ ansible/node/roles/common/templates/chrony.conf.j2 | 41 +++++++ ansible/node/roles/common/templates/hosts.j2 | 10 ++ ansible/node/roles/common/templates/resolv.conf.j2 | 3 + ansible/node/roles/ctdb/tasks/generic/ctdb.yml | 5 + ansible/node/roles/ctdb/tasks/main.yml | 12 ++ ansible/node/roles/ctdb/tasks/redhat/packages.yml | 13 ++ ansible/node/roles/ctdb/templates/ctdb_nodes.j2 | 5 + ansible/node/roles/nas/files/rpc-rquotad.sysconfig | 1 + ansible/node/roles/nas/files/smb.conf | 4 + ansible/node/roles/nas/tasks/generic/ctdb-once.yml | 3 + .../node/roles/nas/tasks/generic/ctdb-start.yml | 12 ++ ansible/node/roles/nas/tasks/generic/ctdb-stop.yml | 5 + .../nas/tasks/generic/ctdb-with-samba-nfs.yml | 41 +++++++ ansible/node/roles/nas/tasks/generic/ctdb.yml | 37 ++++++ ansible/node/roles/nas/tasks/generic/nfs.yml | 5 + .../roles/nas/tasks/generic/samba-gpfs-once.yml | 16 +++ .../node/roles/nas/tasks/generic/samba-once.yml | 12 ++ ansible/node/roles/nas/tasks/generic/samba.yml | 10 ++ ansible/node/roles/nas/tasks/generic/shares.yml | 9 ++ ansible/node/roles/nas/tasks/main.yml | 17 +++ ansible/node/roles/nas/tasks/redhat/nfs.yml | 31 +++++ ansible/node/roles/nas/tasks/redhat/samba.yml | 48 ++++++++ ansible/node/roles/nas/templates/ctdb_conf.j2 | 6 + .../roles/nas/templates/ctdb_public_addresses.j2 | 55 +++++++++ ansible/node/roles/nas/templates/ctdb_sysconfig.j2 | 23 ++++ ansible/node/roles/nas/templates/nfs_exports.j2 | 6 + ansible/node/roles/nas/templates/nfs_sysconfig.j2 | 14 +++ ansible/node/roles/nas/templates/samba_registry.j2 | 33 +++++ ansible/node/roles/nasrepos/tasks/main.yml | 6 + ansible/node/roles/nasrepos/tasks/redhat/repo.yml | 12 ++ .../storage/tasks/generic/clusterfs-gpfs-once.yml | 135 +++++++++++++++++++++ .../roles/storage/tasks/generic/clusterfs-gpfs.yml | 20 +++ ansible/node/roles/storage/tasks/main.yml | 6 + ansible/node/roles/storage/templates/gpfs_nodes.j2 | 33 +++++ .../storage/templates/gpfs_primary_secondary.j2 | 19 +++ ansible/node/site.yml | 8 ++ ansible/node/storage.yml | 8 ++ ansible/node/test.yml | 8 ++ 69 files changed, 1169 insertions(+) create mode 100644 ansible/node/ad.yml create mode 100644 ansible/node/base.yml create mode 100644 ansible/node/build.yml create mode 100644 ansible/node/cbuild.yml create mode 100644 ansible/node/nas.yml create mode 100644 ansible/node/roles/README create mode 100644 ansible/node/roles/ad/tasks/generic/configure_ad.yml create mode 100644 ansible/node/roles/ad/tasks/main.yml create mode 100644 ansible/node/roles/ad/tasks/redhat/packages.yml create mode 100644 ansible/node/roles/build/tasks/main.yml create mode 100644 ansible/node/roles/build/tasks/redhat/packages.yml create mode 100644 ansible/node/roles/build/tasks/redhat/packaging_setup.yml create mode 100644 ansible/node/roles/clusterfs/files/autocluster-gpfs.profile create mode 100644 ansible/node/roles/clusterfs/tasks/main.yml create mode 100644 ansible/node/roles/clusterfs/tasks/redhat/clusterfs-gpfs.yml create mode 100644 ansible/node/roles/clusterfs/tasks/redhat/repo.yml create mode 100644 ansible/node/roles/common/files/rsyslog.conf create mode 100644 ansible/node/roles/common/files/ssh_config create mode 100644 ansible/node/roles/common/handlers/main.yml create mode 100644 ansible/node/roles/common/tasks/generic/autocluster.yml create mode 100644 ansible/node/roles/common/tasks/generic/hosts.yml create mode 100644 ansible/node/roles/common/tasks/generic/mount_home.yml create mode 100644 ansible/node/roles/common/tasks/generic/resolv_conf.yml create mode 100644 ansible/node/roles/common/tasks/generic/rsyslog.yml create mode 100644 ansible/node/roles/common/tasks/generic/selinux.yml create mode 100644 ansible/node/roles/common/tasks/generic/ssh.yml create mode 100644 ansible/node/roles/common/tasks/generic/timezone.yml create mode 100644 ansible/node/roles/common/tasks/main.yml create mode 100644 ansible/node/roles/common/tasks/redhat/firewall.yml create mode 100644 ansible/node/roles/common/tasks/redhat/ntp.yml create mode 100644 ansible/node/roles/common/tasks/redhat/packages.yml create mode 100644 ansible/node/roles/common/templates/chrony.conf.j2 create mode 100644 ansible/node/roles/common/templates/hosts.j2 create mode 100644 ansible/node/roles/common/templates/resolv.conf.j2 create mode 100644 ansible/node/roles/ctdb/tasks/generic/ctdb.yml create mode 100644 ansible/node/roles/ctdb/tasks/main.yml create mode 100644 ansible/node/roles/ctdb/tasks/redhat/packages.yml create mode 100644 ansible/node/roles/ctdb/templates/ctdb_nodes.j2 create mode 100644 ansible/node/roles/nas/files/rpc-rquotad.sysconfig create mode 100644 ansible/node/roles/nas/files/smb.conf create mode 100644 ansible/node/roles/nas/tasks/generic/ctdb-once.yml create mode 100644 ansible/node/roles/nas/tasks/generic/ctdb-start.yml create mode 100644 ansible/node/roles/nas/tasks/generic/ctdb-stop.yml create mode 100644 ansible/node/roles/nas/tasks/generic/ctdb-with-samba-nfs.yml create mode 100644 ansible/node/roles/nas/tasks/generic/ctdb.yml create mode 100644 ansible/node/roles/nas/tasks/generic/nfs.yml create mode 100644 ansible/node/roles/nas/tasks/generic/samba-gpfs-once.yml create mode 100644 ansible/node/roles/nas/tasks/generic/samba-once.yml create mode 100644 ansible/node/roles/nas/tasks/generic/samba.yml create mode 100644 ansible/node/roles/nas/tasks/generic/shares.yml create mode 100644 ansible/node/roles/nas/tasks/main.yml create mode 100644 ansible/node/roles/nas/tasks/redhat/nfs.yml create mode 100644 ansible/node/roles/nas/tasks/redhat/samba.yml create mode 100644 ansible/node/roles/nas/templates/ctdb_conf.j2 create mode 100644 ansible/node/roles/nas/templates/ctdb_public_addresses.j2 create mode 100644 ansible/node/roles/nas/templates/ctdb_sysconfig.j2 create mode 100644 ansible/node/roles/nas/templates/nfs_exports.j2 create mode 100644 ansible/node/roles/nas/templates/nfs_sysconfig.j2 create mode 100644 ansible/node/roles/nas/templates/samba_registry.j2 create mode 100644 ansible/node/roles/nasrepos/tasks/main.yml create mode 100644 ansible/node/roles/nasrepos/tasks/redhat/repo.yml create mode 100644 ansible/node/roles/storage/tasks/generic/clusterfs-gpfs-once.yml create mode 100644 ansible/node/roles/storage/tasks/generic/clusterfs-gpfs.yml create mode 100644 ansible/node/roles/storage/tasks/main.yml create mode 100644 ansible/node/roles/storage/templates/gpfs_nodes.j2 create mode 100644 ansible/node/roles/storage/templates/gpfs_primary_secondary.j2 create mode 100644 ansible/node/site.yml create mode 100644 ansible/node/storage.yml create mode 100644 ansible/node/test.yml diff --git a/ansible/node/ad.yml b/ansible/node/ad.yml new file mode 100644 index 0000000..79e2cc0 --- /dev/null +++ b/ansible/node/ad.yml @@ -0,0 +1,7 @@ +--- +- hosts: ad-nodes + remote_user: root + + roles: + - common + - ad diff --git a/ansible/node/base.yml b/ansible/node/base.yml new file mode 100644 index 0000000..f5e9d5e --- /dev/null +++ b/ansible/node/base.yml @@ -0,0 +1,6 @@ +--- +- hosts: base-nodes + remote_user: root + + roles: + - common diff --git a/ansible/node/build.yml b/ansible/node/build.yml new file mode 100644 index 0000000..fe4023d --- /dev/null +++ b/ansible/node/build.yml @@ -0,0 +1,8 @@ +--- +- hosts: build-nodes + remote_user: root + + roles: + - common + - nasrepos + - build diff --git a/ansible/node/cbuild.yml b/ansible/node/cbuild.yml new file mode 100644 index 0000000..1a3d474 --- /dev/null +++ b/ansible/node/cbuild.yml @@ -0,0 +1,8 @@ +--- +- hosts: cbuild-nodes + remote_user: root + + roles: + - common + - clusterfs + - build diff --git a/ansible/node/nas.yml b/ansible/node/nas.yml new file mode 100644 index 0000000..664f78d --- /dev/null +++ b/ansible/node/nas.yml @@ -0,0 +1,11 @@ +--- +- hosts: nas-nodes + remote_user: root + + roles: + - common + - clusterfs + - nasrepos + - ctdb + - storage + - nas diff --git a/ansible/node/roles/README b/ansible/node/roles/README new file mode 100644 index 0000000..84e9a86 --- /dev/null +++ b/ansible/node/roles/README @@ -0,0 +1,33 @@ +Roles defined: + +common: The basis for all node types + + Includes: + * Firewall disabled + * NTP setup + * NetworkManager disabled + * Repositories set up + * /etc/{hosts,resolv.conf} set yp + * Passwordless ssh enabled between cluster nodes + * Timezone set as configured + * Syslog configured to log with high resolution timestamps + +ad: Samba AD installed and configured + +build: Development and packaging tools installed + +clusterfs: Cluster filesystem is installed + +ctdb: CTDB packages installed, nodes file created + + Depends: nasrepos + +nas: CTDB, Samba, NFS installed and configured + + Depends: clusterfs, nasrepos, ctdb + +nasrepos: Samba/CTDB package repositories configured + +storage: Cluster filesystem configured and accessible + + Depends: clusterfs diff --git a/ansible/node/roles/ad/tasks/generic/configure_ad.yml b/ansible/node/roles/ad/tasks/generic/configure_ad.yml new file mode 100644 index 0000000..c56d1e4 --- /dev/null +++ b/ansible/node/roles/ad/tasks/generic/configure_ad.yml @@ -0,0 +1,65 @@ +--- +- name: check if AD server active flag file exists + stat: + path: /root/.autocluster/ad_active + register: ad_active + +- name: remove smb.conf + file: + path: /etc/samba/smb.conf + state: absent + when: not ad_active.stat.exists + +- name: provision domain + command: > + samba-tool domain provision + --server-role="dc" + --use-rfc2307 + --dns-backend="SAMBA_INTERNAL" + --realm="{{ resolv_conf.domain }}" + --domain="{{ samba.workgroup }}" + --adminpass="{{ ad.admin_password }}" + --host-ip={{ nodes[ansible_hostname].ips[0] }} + --option="dns forwarder = {{ ad.dns_forwarder }}" + when: not ad_active.stat.exists + +- name: add users and groups + command: samba-tool {{ p }} + with_list: + - domain passwordsettings set --min-pwd-length=3 + - domain passwordsettings set --complexity=off + - user setexpiry --noexpiry Administrator + - user setpassword administrator --newpassword="{{ ad.admin_password }}" + - group add group1 + - group add group2 + - user add user1 "{{ ad.admin_password }}" + - group addmembers group1 user1 + - user setexpiry --noexpiry user1 + - user add user2 "{{ ad.admin_password }}" + - group addmembers group2 user2 + - user setexpiry --noexpiry user2 + loop_control: + loop_var: p + when: not ad_active.stat.exists + +# This is created from a template in common/. It might be good not to +# update this twice but we probably want a working configuration under +# the DC is started below. +- name: update /etc/resolv.conf + lineinfile: + path: /etc/resolv.conf + regexp: "^nameserver.*" + line: "nameserver {{ nodes[ansible_hostname].ips[0] }}" + when: not ad_active.stat.exists + +- name: ensure domain controller is enabled and running + service: + name: samba + state: started + enabled: yes + when: not ad_active.stat.exists + +- name: flag AD server as active + file: + path: /root/.autocluster/ad_active + state: touch diff --git a/ansible/node/roles/ad/tasks/main.yml b/ansible/node/roles/ad/tasks/main.yml new file mode 100644 index 0000000..6b0e811 --- /dev/null +++ b/ansible/node/roles/ad/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - packages + loop_control: + loop_var: task + +- include_tasks: generic/{{ task }}.yml + with_list: + - configure_ad + loop_control: + loop_var: task diff --git a/ansible/node/roles/ad/tasks/redhat/packages.yml b/ansible/node/roles/ad/tasks/redhat/packages.yml new file mode 100644 index 0000000..49d1eaf --- /dev/null +++ b/ansible/node/roles/ad/tasks/redhat/packages.yml @@ -0,0 +1,22 @@ +--- +- name: Add Samba AD repos + yum_repository: + name: "autocluster-{{ repo.name }}" + description: "{{ repo.name }}" + baseurl: "{{ repo.baseurl | default(repository_baseurl) }}/{{ repo.path }}" + gpgcheck: no + proxy: _none_ + when: repo.type == "ad" + with_list: "{{ repositories }}" + loop_control: + loop_var: repo + +- name: FIXME - create /run/samba directory + file: + path: /run/samba + state: directory + +- name: install packages for Active Directory node + package: + name: samba-dc + state: present diff --git a/ansible/node/roles/build/tasks/main.yml b/ansible/node/roles/build/tasks/main.yml new file mode 100644 index 0000000..5e6cd27 --- /dev/null +++ b/ansible/node/roles/build/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - packages + - packaging_setup + loop_control: + loop_var: task diff --git a/ansible/node/roles/build/tasks/redhat/packages.yml b/ansible/node/roles/build/tasks/redhat/packages.yml new file mode 100644 index 0000000..1b0d485 --- /dev/null +++ b/ansible/node/roles/build/tasks/redhat/packages.yml @@ -0,0 +1,24 @@ +--- +- name: install packages for build node + package: + name: + - git + # RPM development + - rpmdevtools + # Performance co-pilot to allow build of CTDB pmda code + - pcp-libs + - pcp-libs-devel + # Building Samba + - readline-devel + - libacl-devel + - e2fsprogs-devel + - libxslt + - docbook-utils + - docbook-style-xsl + - dbus-devel + - libaio-devel + - libcap-devel + - quota-devel + - perl-Parse-Yapp + - perl-ExtUtils-MakeMaker + state: present diff --git a/ansible/node/roles/build/tasks/redhat/packaging_setup.yml b/ansible/node/roles/build/tasks/redhat/packaging_setup.yml new file mode 100644 index 0000000..7415960 --- /dev/null +++ b/ansible/node/roles/build/tasks/redhat/packaging_setup.yml @@ -0,0 +1,8 @@ +--- +- name: Setup the RPM directory tree + command: rpmdev-setuptree + +- name: Remove .rpmmacros + file: + path: /root/.rpmmacros + state: absent diff --git a/ansible/node/roles/clusterfs/files/autocluster-gpfs.profile b/ansible/node/roles/clusterfs/files/autocluster-gpfs.profile new file mode 100644 index 0000000..71c610d --- /dev/null +++ b/ansible/node/roles/clusterfs/files/autocluster-gpfs.profile @@ -0,0 +1,2 @@ +# Added by autocluster +pathmunge /usr/lpp/mmfs/bin diff --git a/ansible/node/roles/clusterfs/tasks/main.yml b/ansible/node/roles/clusterfs/tasks/main.yml new file mode 100644 index 0000000..6e3ec1a --- /dev/null +++ b/ansible/node/roles/clusterfs/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - repo + - clusterfs-{{ clusterfs.type }} + loop_control: + loop_var: task diff --git a/ansible/node/roles/clusterfs/tasks/redhat/clusterfs-gpfs.yml b/ansible/node/roles/clusterfs/tasks/redhat/clusterfs-gpfs.yml new file mode 100644 index 0000000..c77e380 --- /dev/null +++ b/ansible/node/roles/clusterfs/tasks/redhat/clusterfs-gpfs.yml @@ -0,0 +1,20 @@ +--- +- name: install GPFS packages + package: + name: + - gpfs.base + - gpfs.docs + - gpfs.gpl + - gpfs.msg.en_US + - gpfs.gskit + state: present + +- name: install GPFS /etc/profile.d/ snippet + copy: + src: autocluster-gpfs.profile + dest: /etc/profile.d/autocluster-gpfs.sh + +- name: build GPFS modules + shell: LINUX_DISTRIBUTION=REDHAT_AS_LINUX /usr/lpp/mmfs/bin/mmbuildgpl + args: + chdir: /usr/lpp/mmfs/src diff --git a/ansible/node/roles/clusterfs/tasks/redhat/repo.yml b/ansible/node/roles/clusterfs/tasks/redhat/repo.yml new file mode 100644 index 0000000..0000ccd --- /dev/null +++ b/ansible/node/roles/clusterfs/tasks/redhat/repo.yml @@ -0,0 +1,12 @@ +--- +- name: Add cluster filesystem repos + yum_repository: + name: "autocluster-{{ repo.name }}" + description: "{{ repo.name }}" + baseurl: "{{ repo.baseurl | default(repository_baseurl) }}/{{ repo.path }}" + gpgcheck: no + proxy: _none_ + when: repo.type == "clusterfs" + with_list: "{{ repositories }}" + loop_control: + loop_var: repo diff --git a/ansible/node/roles/common/files/rsyslog.conf b/ansible/node/roles/common/files/rsyslog.conf new file mode 100644 index 0000000..6478b45 --- /dev/null +++ b/ansible/node/roles/common/files/rsyslog.conf @@ -0,0 +1,14 @@ +# Select a high precision time format. This allows accurate merging +# of logs from multiple cluster nodes for easier CTDB debugging. +$ActionFileDefaultTemplate RSYSLOG_FileFormat + +# Turn off rate-limiting. Why would we want to lose messages by +# default? +$SystemLogRateLimitInterval 0 +$SystemLogRateLimitBurst 0 + +# Turn on UDP listener to be able to take advantage of CTDB's new +# direct-to-syslog-on-UDP feature. +$ModLoad imudp +$UDPServerAddress 127.0.0.1 +$UDPServerRun 514 diff --git a/ansible/node/roles/common/files/ssh_config b/ansible/node/roles/common/files/ssh_config new file mode 100644 index 0000000..de7ff06 --- /dev/null +++ b/ansible/node/roles/common/files/ssh_config @@ -0,0 +1,2 @@ +StrictHostKeyChecking no +IdentityFile ~/.ssh/id_autocluster diff --git a/ansible/node/roles/common/handlers/main.yml b/ansible/node/roles/common/handlers/main.yml new file mode 100644 index 0000000..1b033cb --- /dev/null +++ b/ansible/node/roles/common/handlers/main.yml @@ -0,0 +1,12 @@ +--- +# Including handlers and conditional handlers seem broken :-( + +- name: restart NTP server redhat + service: + name: chronyd + state: restarted + +- name: restart rsyslog + service: + name: rsyslog + state: restarted diff --git a/ansible/node/roles/common/tasks/generic/autocluster.yml b/ansible/node/roles/common/tasks/generic/autocluster.yml new file mode 100644 index 0000000..753b225 --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/autocluster.yml @@ -0,0 +1,5 @@ +--- +- name: create autocluster state directory + file: + path: /root/.autocluster + state: directory diff --git a/ansible/node/roles/common/tasks/generic/hosts.yml b/ansible/node/roles/common/tasks/generic/hosts.yml new file mode 100644 index 0000000..6983826 --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/hosts.yml @@ -0,0 +1,5 @@ +--- +- name: create /etc/hosts + template: + src: hosts.j2 + dest: /etc/hosts diff --git a/ansible/node/roles/common/tasks/generic/mount_home.yml b/ansible/node/roles/common/tasks/generic/mount_home.yml new file mode 100644 index 0000000..8a49816 --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/mount_home.yml @@ -0,0 +1,12 @@ +--- +- name: ensure that an fstab entry exists to NFS mount /home + lineinfile: + path: /etc/fstab + regexp: '^.*:/home /home nfs.*' + # Do not use locking, since this starts/needs rpc.statd, which is + # stopped/started by CTDB + line: '{{ virthost }}:/home /home nfs nfsvers=3,intr,nolock 0 0' + +- name: ensure that /home is mounted + shell: > + findmnt -n /home || mount /home diff --git a/ansible/node/roles/common/tasks/generic/resolv_conf.yml b/ansible/node/roles/common/tasks/generic/resolv_conf.yml new file mode 100644 index 0000000..b6704ee --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/resolv_conf.yml @@ -0,0 +1,5 @@ +--- +- name: configure resolver + template: + src: resolv.conf.j2 + dest: /etc/resolv.conf diff --git a/ansible/node/roles/common/tasks/generic/rsyslog.yml b/ansible/node/roles/common/tasks/generic/rsyslog.yml new file mode 100644 index 0000000..88535af --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/rsyslog.yml @@ -0,0 +1,7 @@ +--- +- name: add autocluster-specific rsyslog configuration + copy: + src: rsyslog.conf + dest: /etc/rsyslog.d/autocluster.conf + notify: + - restart rsyslog diff --git a/ansible/node/roles/common/tasks/generic/selinux.yml b/ansible/node/roles/common/tasks/generic/selinux.yml new file mode 100644 index 0000000..b7e9c2f --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/selinux.yml @@ -0,0 +1,4 @@ +--- +- selinux: + policy: targeted + state: permissive diff --git a/ansible/node/roles/common/tasks/generic/ssh.yml b/ansible/node/roles/common/tasks/generic/ssh.yml new file mode 100644 index 0000000..c3bff9f --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/ssh.yml @@ -0,0 +1,5 @@ +--- +- name: configure passwordless SSH + copy: + src: ssh_config + dest: /root/.ssh/config diff --git a/ansible/node/roles/common/tasks/generic/timezone.yml b/ansible/node/roles/common/tasks/generic/timezone.yml new file mode 100644 index 0000000..87b0ba4 --- /dev/null +++ b/ansible/node/roles/common/tasks/generic/timezone.yml @@ -0,0 +1,12 @@ +--- +- name: configure node timezone + timezone: + hwclock: UTC + name: "{{timezone}}" + +- name: hand hack timezone to avoid reboot + file: + src: /usr/share/zoneinfo/{{timezone}} + path: /etc/localtime + state: link + force: yes diff --git a/ansible/node/roles/common/tasks/main.yml b/ansible/node/roles/common/tasks/main.yml new file mode 100644 index 0000000..104d9f5 --- /dev/null +++ b/ansible/node/roles/common/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - packages + - firewall + - ntp + loop_control: + loop_var: task + +- meta: flush_handlers + +- include_tasks: generic/{{ task }}.yml + with_list: + - selinux + - autocluster + - hosts + - resolv_conf + - ssh + - timezone + - rsyslog + - mount_home + loop_control: + loop_var: task + +- meta: flush_handlers diff --git a/ansible/node/roles/common/tasks/redhat/firewall.yml b/ansible/node/roles/common/tasks/redhat/firewall.yml new file mode 100644 index 0000000..bf5eeb4 --- /dev/null +++ b/ansible/node/roles/common/tasks/redhat/firewall.yml @@ -0,0 +1,6 @@ +--- +- name: disable firewall + service: + name: firewalld + enabled: no + state: stopped diff --git a/ansible/node/roles/common/tasks/redhat/ntp.yml b/ansible/node/roles/common/tasks/redhat/ntp.yml new file mode 100644 index 0000000..3495457 --- /dev/null +++ b/ansible/node/roles/common/tasks/redhat/ntp.yml @@ -0,0 +1,18 @@ +--- +- name: ensure NTP server is installed + package: + name: chrony + state: installed + +- name: ensure NTP server is configured + template: + src: chrony.conf.j2 + dest: /etc/chrony.conf + notify: + - restart NTP server redhat + +- name: ensure NTP server is running and enabled + service: + name: chronyd + state: started + enabled: yes diff --git a/ansible/node/roles/common/tasks/redhat/packages.yml b/ansible/node/roles/common/tasks/redhat/packages.yml new file mode 100644 index 0000000..b2430e5 --- /dev/null +++ b/ansible/node/roles/common/tasks/redhat/packages.yml @@ -0,0 +1,53 @@ +--- +- name: disable Network Manager on next boot + service: + name: NetworkManager + enabled: no + # Note that this only works because the interfaces of interest + # have been marked in Vagrant as: nm_controlled: "no" - otherwise + # NetworkManager would stop and take the interfaces down with it! + state: stopped + +- name: disable EPEL to speed things up + package: + name: epel-release + state: absent + +- name: find non-autocluster YUM repo files + find: + paths: /etc/yum.repos.d/ + patterns: '(?!autocluster-)^.*\.repo$' + use_regex: yes + register: find_results + when: repositories_delete_existing + +- name: Remove non-autocluster repo files + file: + path: "{{ f['path'] }}" + state: absent + with_list: "{{ find_results['files'] }}" + loop_control: + loop_var: f + when: repositories_delete_existing + +- name: Add local distro repos + yum_repository: + name: "autocluster-{{ repo.name }}" + description: "{{ repo.name }}" + baseurl: "{{ repo.baseurl | default(repository_baseurl) }}/{{ repo.path }}" + gpgcheck: "{{ repo.gpgcheck | default('yes') }}" + proxy: _none_ + when: repo.type == "distro" + with_list: "{{ repositories }}" + loop_control: + loop_var: repo + +- name: ensure optional dependencies for Ansible template handling + package: + name: libselinux-python + state: present + +- name: ensure NFS client tools are installed + package: + name: nfs-utils + state: present diff --git a/ansible/node/roles/common/templates/chrony.conf.j2 b/ansible/node/roles/common/templates/chrony.conf.j2 new file mode 100644 index 0000000..2a4f259 --- /dev/null +++ b/ansible/node/roles/common/templates/chrony.conf.j2 @@ -0,0 +1,41 @@ +server {{virthost}} iburst + +# Ignore stratum in source selection. +stratumweight 0 + +# Record the rate at which the system clock gains/losses time. +driftfile /var/lib/chrony/drift + +# Enable kernel RTC synchronization. +rtcsync + +# In first three updates step the system clock instead of slew +# if the adjustment is larger than 10 seconds. +makestep 10 3 + +# Allow NTP client access from local network. +#allow 192.168/16 + +# Listen for commands only on localhost. +bindcmdaddress 127.0.0.1 +bindcmdaddress ::1 + +# Serve time even if not synchronized to any NTP server. +#local stratum 10 + +keyfile /etc/chrony.keys + +# Specify the key used as password for chronyc. +commandkey 1 + +# Generate command key if missing. +generatecommandkey + +# Disable logging of client accesses. +noclientlog + +# Send a message to syslog if a clock adjustment is larger than 0.5 seconds. +logchange 0.5 + +logdir /var/log/chrony +#log measurements statistics tracking diff --git a/ansible/node/roles/common/templates/hosts.j2 b/ansible/node/roles/common/templates/hosts.j2 new file mode 100644 index 0000000..c575ea2 --- /dev/null +++ b/ansible/node/roles/common/templates/hosts.j2 @@ -0,0 +1,10 @@ +# Generated by autocluster +127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 +::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 + +{{ virthost }} kvmhost + +# autocluster {{ cluster }} +{% for hostname, n in nodes | dictsort %} +{{ n.ips[0] }} {{ hostname }}.{{ resolv_conf.domain | lower }} {{ hostname }} +{% endfor %} diff --git a/ansible/node/roles/common/templates/resolv.conf.j2 b/ansible/node/roles/common/templates/resolv.conf.j2 new file mode 100644 index 0000000..7ebaf95 --- /dev/null +++ b/ansible/node/roles/common/templates/resolv.conf.j2 @@ -0,0 +1,3 @@ +domain {{resolv_conf.domain}} +search {{resolv_conf.search}} +nameserver {{resolv_conf.nameserver}} diff --git a/ansible/node/roles/ctdb/tasks/generic/ctdb.yml b/ansible/node/roles/ctdb/tasks/generic/ctdb.yml new file mode 100644 index 0000000..350aeeb --- /dev/null +++ b/ansible/node/roles/ctdb/tasks/generic/ctdb.yml @@ -0,0 +1,5 @@ +--- +- name: generate CTDB nodes file + template: + src: ctdb_nodes.j2 + dest: /etc/ctdb/nodes diff --git a/ansible/node/roles/ctdb/tasks/main.yml b/ansible/node/roles/ctdb/tasks/main.yml new file mode 100644 index 0000000..5259448 --- /dev/null +++ b/ansible/node/roles/ctdb/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - packages + loop_control: + loop_var: task + +- include_tasks: generic/{{ task }}.yml + with_list: + - ctdb + loop_control: + loop_var: task diff --git a/ansible/node/roles/ctdb/tasks/redhat/packages.yml b/ansible/node/roles/ctdb/tasks/redhat/packages.yml new file mode 100644 index 0000000..7bd6ca6 --- /dev/null +++ b/ansible/node/roles/ctdb/tasks/redhat/packages.yml @@ -0,0 +1,13 @@ +--- +- name: install CTDB packages + package: + name: + - ctdb + - ctdb-debuginfo + - ctdb-tests + state: present + +- name: install tcpdump + package: + name: tcpdump + state: present diff --git a/ansible/node/roles/ctdb/templates/ctdb_nodes.j2 b/ansible/node/roles/ctdb/templates/ctdb_nodes.j2 new file mode 100644 index 0000000..7094678 --- /dev/null +++ b/ansible/node/roles/ctdb/templates/ctdb_nodes.j2 @@ -0,0 +1,5 @@ +{% for hostname, n in nodes | dictsort %} +{% if n.is_ctdb_node %} +{{ n.ips[0] }} +{% endif %} +{% endfor %} diff --git a/ansible/node/roles/nas/files/rpc-rquotad.sysconfig b/ansible/node/roles/nas/files/rpc-rquotad.sysconfig new file mode 100644 index 0000000..93f7089 --- /dev/null +++ b/ansible/node/roles/nas/files/rpc-rquotad.sysconfig @@ -0,0 +1 @@ +RPCRQUOTADOPTS="-p 32768" diff --git a/ansible/node/roles/nas/files/smb.conf b/ansible/node/roles/nas/files/smb.conf new file mode 100644 index 0000000..5c8ead3 --- /dev/null +++ b/ansible/node/roles/nas/files/smb.conf @@ -0,0 +1,4 @@ +[global] + clustering=yes + ctdb:registry.tdb=yes + include=registry diff --git a/ansible/node/roles/nas/tasks/generic/ctdb-once.yml b/ansible/node/roles/nas/tasks/generic/ctdb-once.yml new file mode 100644 index 0000000..139bd32 --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/ctdb-once.yml @@ -0,0 +1,3 @@ +--- +- name: set security context for CTDB recovery lock directory + command: chcon -t ctdbd_var_t {{ clusterfs.mountpoint }}/.ctdb diff --git a/ansible/node/roles/nas/tasks/generic/ctdb-start.yml b/ansible/node/roles/nas/tasks/generic/ctdb-start.yml new file mode 100644 index 0000000..8bc9dbb --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/ctdb-start.yml @@ -0,0 +1,12 @@ +--- +- name: start CTDB + service: + name: ctdb + state: started + +- name: wait until CTDB is healthy + command: ctdb nodestatus all + register: result + until: result.rc == 0 + retries: 24 + delay: 5 diff --git a/ansible/node/roles/nas/tasks/generic/ctdb-stop.yml b/ansible/node/roles/nas/tasks/generic/ctdb-stop.yml new file mode 100644 index 0000000..ca624dc --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/ctdb-stop.yml @@ -0,0 +1,5 @@ +--- +- name: stop CTDB + service: + name: ctdb + state: stopped diff --git a/ansible/node/roles/nas/tasks/generic/ctdb-with-samba-nfs.yml b/ansible/node/roles/nas/tasks/generic/ctdb-with-samba-nfs.yml new file mode 100644 index 0000000..dea44fa --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/ctdb-with-samba-nfs.yml @@ -0,0 +1,41 @@ +--- +# Should be running already but this won't hurt +- import_tasks: ctdb-start.yml + +- name: join active directory domain + shell: | + net ads testjoin || \ + timeout 10 net ads join -U "administrator%{{ ad.admin_password }}" + register: result + until: result.rc == 0 + retries: 5 + delay: 1 + run_once: true + when: auth_method == 'winbind' + +# FIXME: This will be useful to allow version checking to enable +# services/event scripts in different ways + +# New in Ansible 2.5 +#- name: get package facts +# package_facts: +# manager: "auto" + +#- name: show them +# debug: var=ansible_facts.packages + +- import_tasks: ctdb-stop.yml + +- name: configure CTDB to manage smbd and NFS + command: ctdb event script enable legacy {{ s }} + with_list: + - 50.samba + - 60.nfs + loop_control: + loop_var: s + +- name: configure CTDB to manage winbindd + command: ctdb event script enable legacy 49.winbind + when: auth_method == 'winbind' + +- import_tasks: ctdb-start.yml diff --git a/ansible/node/roles/nas/tasks/generic/ctdb.yml b/ansible/node/roles/nas/tasks/generic/ctdb.yml new file mode 100644 index 0000000..5041db4 --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/ctdb.yml @@ -0,0 +1,37 @@ +--- +- name: generate CTDB configuration file + template: + src: ctdb_conf.j2 + dest: /etc/ctdb/ctdb.conf + +- name: generate CTDB public addresses file + template: + src: ctdb_public_addresses.j2 + dest: /etc/ctdb/public_addresses + +- name: create directory for CTDB recovery lock + file: + path: "{{ clusterfs.mountpoint }}/.ctdb" + state: directory + +- import_tasks: ctdb-once.yml + run_once: true + +- name: ensure CTDB is enabled + service: + name: ctdb + enabled: yes + +# This stops things failing if the domain has not been joined or similar +- name: ensure that CTDB is not managing smbd, winbind and NFS + command: ctdb event script disable legacy {{ s }} + with_list: + - 49.winbind + - 50.samba + - 60.nfs + loop_control: + loop_var: s + +# Restart just in case ctdbd was running but unhealthy +- import_tasks: ctdb-stop.yml +- import_tasks: ctdb-start.yml diff --git a/ansible/node/roles/nas/tasks/generic/nfs.yml b/ansible/node/roles/nas/tasks/generic/nfs.yml new file mode 100644 index 0000000..90c00bc --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/nfs.yml @@ -0,0 +1,5 @@ +--- +- name: generate NFS exports file + template: + src: nfs_exports.j2 + dest: /etc/exports diff --git a/ansible/node/roles/nas/tasks/generic/samba-gpfs-once.yml b/ansible/node/roles/nas/tasks/generic/samba-gpfs-once.yml new file mode 100644 index 0000000..101cd4b --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/samba-gpfs-once.yml @@ -0,0 +1,16 @@ +--- +- name: Tweak Samba config for GPFS cluster filesystem + command: net conf setparm global "{{ p.param }}" "{{ p.value }}" + with_list: + - param: vfs objects + value: gpfs fileid + - param: fileid:mapping + value: fsname + - param: nfs4:chown + value: "yes" + - param: nfs4:acedup + value: merge + - param: force unknown acl user + value: "yes" + loop_control: + loop_var: p diff --git a/ansible/node/roles/nas/tasks/generic/samba-once.yml b/ansible/node/roles/nas/tasks/generic/samba-once.yml new file mode 100644 index 0000000..8a586e6 --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/samba-once.yml @@ -0,0 +1,12 @@ +--- +- name: generate initial Samba registry configuration + template: + src: samba_registry.j2 + dest: /root/.autocluster/samba-registry.conf + +# Need to start at least ctdbd... maybe smbd? + +- name: initialise Samba registry configuration + command: net conf import /root/.autocluster/samba-registry.conf + +- import_tasks: samba-{{ clusterfs.type }}-once.yml diff --git a/ansible/node/roles/nas/tasks/generic/samba.yml b/ansible/node/roles/nas/tasks/generic/samba.yml new file mode 100644 index 0000000..c1e58b8 --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/samba.yml @@ -0,0 +1,10 @@ +--- +- name: add smb.conf + copy: + src: smb.conf + dest: /etc/samba/smb.conf + +# TODO: Enable 50.samba and 60.nfs event scripts + +- import_tasks: samba-once.yml + run_once: true diff --git a/ansible/node/roles/nas/tasks/generic/shares.yml b/ansible/node/roles/nas/tasks/generic/shares.yml new file mode 100644 index 0000000..db5d58e --- /dev/null +++ b/ansible/node/roles/nas/tasks/generic/shares.yml @@ -0,0 +1,9 @@ +--- +- name: create share directories + file: + path: "{{s.directory}}" + mode: "{{s.mode}}" + state: directory + with_list: "{{shares}}" + loop_control: + loop_var: s diff --git a/ansible/node/roles/nas/tasks/main.yml b/ansible/node/roles/nas/tasks/main.yml new file mode 100644 index 0000000..6d56084 --- /dev/null +++ b/ansible/node/roles/nas/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - samba + - nfs + loop_control: + loop_var: task + +- include_tasks: generic/{{ task }}.yml + with_list: + - shares + - ctdb + - samba + - nfs + - ctdb-with-samba-nfs + loop_control: + loop_var: task diff --git a/ansible/node/roles/nas/tasks/redhat/nfs.yml b/ansible/node/roles/nas/tasks/redhat/nfs.yml new file mode 100644 index 0000000..4dc1d7c --- /dev/null +++ b/ansible/node/roles/nas/tasks/redhat/nfs.yml @@ -0,0 +1,31 @@ +--- +- name: install NFS packages + package: + name: nfs-utils + state: present + +- name: ensure NFS does not autostart + service: + name: "{{ s }}" + enabled: no + with_list: + - nfs + - nfslock + loop_control: + loop_var: s + +- name: generate NFS configuration + template: + src: nfs_sysconfig.j2 + dest: /etc/sysconfig/nfs + +- name: check if /etc/sysconfig/rpc-rquotad exists + stat: + path: /etc/sysconfig/rpc-rquotad + register: sysconfig_rpc_rquotad + +- name: generate quota configuration file + file: + src: rpc-rquotad.sysconfig + path: /etc/sysconfig/rpc-rquotad + when: sysconfig_rpc_rquotad.stat.exists diff --git a/ansible/node/roles/nas/tasks/redhat/samba.yml b/ansible/node/roles/nas/tasks/redhat/samba.yml new file mode 100644 index 0000000..ebcd7fb --- /dev/null +++ b/ansible/node/roles/nas/tasks/redhat/samba.yml @@ -0,0 +1,48 @@ +--- + +- name: install Samba packages + package: + name: + - tdb-tools + - samba + - samba-client + - samba-doc + - samba-winbind + - samba-winbind-clients + state: present + +- name: install Samba packages for GPFS + package: + name: samba-vfs-gpfs + state: present + when: clusterfs.type == 'gpfs' + +- name: ensure Samba does not autostart + service: + name: "{{ service }}" + enabled: no + with_list: + - smb + - nmb + - winbind + loop_control: + loop_var: service + +- name: Set up NSS, PAM, ... + command: > + authconfig --update --nostart + --disablewinbindauth --disablewinbind --disablekrb5 + when: auth_method == 'files' + +- name: Set up NSS, PAM, KRB5, ... + command: > + authconfig --update --nostart + --enablewinbindauth --enablewinbind --enablekrb5 + --krb5kdc={{ kdc }}.{{ resolv_conf.domain }} + --krb5realm={{ resolv_conf.domain }} + when: auth_method == 'winbind' + +- name: Set up NSS, PAM, KRB5, ... + fail: + msg: "Invalid auth_method: {{ auth_method }}" + when: auth_method != 'files' and auth_method != 'winbind' diff --git a/ansible/node/roles/nas/templates/ctdb_conf.j2 b/ansible/node/roles/nas/templates/ctdb_conf.j2 new file mode 100644 index 0000000..fbfaead --- /dev/null +++ b/ansible/node/roles/nas/templates/ctdb_conf.j2 @@ -0,0 +1,6 @@ +[logging] + location = syslog + log level = NOTICE + +[cluster] + recovery lock = {{ clusterfs.mountpoint }}/.ctdb/recovery.lock diff --git a/ansible/node/roles/nas/templates/ctdb_public_addresses.j2 b/ansible/node/roles/nas/templates/ctdb_public_addresses.j2 new file mode 100644 index 0000000..77f95b7 --- /dev/null +++ b/ansible/node/roles/nas/templates/ctdb_public_addresses.j2 @@ -0,0 +1,55 @@ +{# #} +{# How many static public addresses/interfaces per node? #} +{# #} +{% set num_static = (nodes[ansible_hostname].ips | length) - 1 %} +{# #} +{# Gather all static addresses, sublist per interface #} +{# #} +{% set static_addrs = [] %} +{% for i in range(1, num_static + 1) -%} +{{ static_addrs.append([]) }} +{%- endfor %} +{% for hostname, n in nodes | dictsort %} +{% if n.is_ctdb_node %} +{% for i in range(1, num_static + 1) -%} +{{ static_addrs[i - 1].append(n.ips[i]) }} +{%- endfor %} +{% endif %} +{% endfor %} +{# #} +{# For each list of static IPs, find interface, print with each IP #} +{# #} +{% set h = ansible_hostname %} +{% for ips in static_addrs %} +{% for iface in ansible_interfaces %} +{% set ai = 'ansible_%s'|format(iface) %} +{% if hostvars[h][ai]['ipv4'] is defined %} +{% set ip4 = hostvars[h][ai]['ipv4'] %} +{% if ip4['address'] is defined %} +{% set aip = ip4['address'] %} +{% set netmask = ip4['netmask'] %} +{% set prefix = (aip + '/' + netmask) | ipv4('prefix') %} +{% if aip in ips %} +{% for ip in ips %} +{% set ip_int = ip | ipaddr('int') %} +{{ (ip_int + 100) | ipaddr('address') }}/{{ prefix }} {{ iface }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} +{% if hostvars[h][ai]['ipv6'] is defined %} +{% for ip6 in hostvars[h][ai]['ipv6'] %} +{% if ip6['address'] is defined %} +{% set aip = ip6['address'] %} +{% set prefix = ip6['prefix'] %} +{% if aip in ips %} +{% for ip in ips %} +{% set ip_int = ip | ipaddr('int') %} +{{ (ip_int + 100) | ipaddr('address') }}/{{ prefix }} {{ iface }} +{% endfor %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +{% endfor %} diff --git a/ansible/node/roles/nas/templates/ctdb_sysconfig.j2 b/ansible/node/roles/nas/templates/ctdb_sysconfig.j2 new file mode 100644 index 0000000..9992023 --- /dev/null +++ b/ansible/node/roles/nas/templates/ctdb_sysconfig.j2 @@ -0,0 +1,23 @@ +# Core +CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses +CTDB_RECOVERY_LOCK={{ clusterfs.mountpoint }}/.ctdb/recovery.lock + +# Services managed +CTDB_MANAGES_SAMBA=yes +{% if auth_method == 'winbind' %} +CTDB_MANAGES_WINBIND=yes +{% else %} +CTDB_MANAGES_WINBIND=no +{% endif %} + +CTDB_MANAGES_NFS=yes +CTDB_MANAGES_HTTPD=yes +CTDB_MANAGES_VSFTPD=yes + +# System +ulimit -n 1048576 +ulimit -c unlimited + +# Logging +CTDB_LOGGING="syslog" +CTDB_DEBUGLEVEL=NOTICE diff --git a/ansible/node/roles/nas/templates/nfs_exports.j2 b/ansible/node/roles/nas/templates/nfs_exports.j2 new file mode 100644 index 0000000..00bd867 --- /dev/null +++ b/ansible/node/roles/nas/templates/nfs_exports.j2 @@ -0,0 +1,6 @@ +# NFS exports file generated by autocluster +{% set fsid = 834258092 %} +{% for s in shares %} +"{{ s.directory }}" *(rw,no_root_squash,subtree_check,fsid={{ fsid }}) + {% set fsid = fsid + 1 %} +{% endfor %} diff --git a/ansible/node/roles/nas/templates/nfs_sysconfig.j2 b/ansible/node/roles/nas/templates/nfs_sysconfig.j2 new file mode 100644 index 0000000..c103fc7 --- /dev/null +++ b/ansible/node/roles/nas/templates/nfs_sysconfig.j2 @@ -0,0 +1,14 @@ +NFS_HOSTNAME="{{ cluster }}" + +STATD_PORT=32765 +STATD_OUTGOING_PORT=32766 +MOUNTD_PORT=32767 +RQUOTAD_PORT=32768 +LOCKD_UDPPORT=32769 +LOCKD_TCPPORT=32769 + +STATDARG="-n ${NFS_HOSTNAME}" +STATD_HA_CALLOUT="/etc/ctdb/statd-callout" + +RPCNFSDARGS="-N 4" +RPCNFSDCOUNT=8 diff --git a/ansible/node/roles/nas/templates/samba_registry.j2 b/ansible/node/roles/nas/templates/samba_registry.j2 new file mode 100644 index 0000000..f6200af --- /dev/null +++ b/ansible/node/roles/nas/templates/samba_registry.j2 @@ -0,0 +1,33 @@ +[global] +{% if auth_method == 'winbind' %} + security = ADS +{% elif auth_method == 'files' %} + security = USER +{% else %} + security = BROKEN +{% endif %} + + logging = syslog + log level = 1 + + netbios name = {{ cluster }} + workgroup = {{ samba.workgroup }} + realm = {{ resolv_conf.domain }} + + disable netbios = yes + disable spoolss = yes + + idmap config * : backend = autorid + idmap config * : range = 1000000-1999999 + + kernel oplocks = yes + + read only = no + +{% for s in shares %} +[{{ s.name }}] + path = {{ s.directory }} + comment = Example share {{ s.name }} + guest ok = yes + browseable = yes +{% endfor %} diff --git a/ansible/node/roles/nasrepos/tasks/main.yml b/ansible/node/roles/nasrepos/tasks/main.yml new file mode 100644 index 0000000..69a1776 --- /dev/null +++ b/ansible/node/roles/nasrepos/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- include_tasks: "{{ ansible_os_family | lower }}/{{ task }}.yml" + with_list: + - repo + loop_control: + loop_var: task diff --git a/ansible/node/roles/nasrepos/tasks/redhat/repo.yml b/ansible/node/roles/nasrepos/tasks/redhat/repo.yml new file mode 100644 index 0000000..d330d08 --- /dev/null +++ b/ansible/node/roles/nasrepos/tasks/redhat/repo.yml @@ -0,0 +1,12 @@ +--- +- name: Add NAS (Samba/CTDB) repos + yum_repository: + name: "autocluster-{{ repo.name }}" + description: "{{ repo.name }}" + baseurl: "{{ repo.baseurl | default(repository_baseurl) }}/{{ repo.path }}" + gpgcheck: no + proxy: _none_ + when: repo.type == "nas" + with_list: "{{ repositories }}" + loop_control: + loop_var: repo diff --git a/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs-once.yml b/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs-once.yml new file mode 100644 index 0000000..5ed26eb --- /dev/null +++ b/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs-once.yml @@ -0,0 +1,135 @@ +--- +- name: generate GPFS nodes file + template: + src: gpfs_nodes.j2 + dest: /root/.autocluster/gpfs_nodes + +- name: generate file containing GPFS primary and secondary nodes + template: + src: gpfs_primary_secondary.j2 + dest: /root/.autocluster/gpfs_primary_secondary + +- name: check if GPFS active flag file exists + stat: + path: /root/.autocluster/gpfs_active + register: gpfs_active + +- name: create GPFS cluster + shell: | + mmlscluster || { + read primary secondary 1 && $9 != "active" { exit(1) }' + register: result + until: result.rc == 0 + retries: 12 + delay: 5 + when: not gpfs_active.stat.exists + +- name: flag GPFS as active + file: + path: /root/.autocluster/gpfs_active + state: touch + +- name: generate NSD file + shell: > + ls /dev/disk/by-id/virtio-AUTO-* | + xargs -n 1 realpath | + awk '{printf "%nsd:\n device=%s\n usage=dataAndMetadata\n failureGroup=1\n\n", $1}' | + tee gpfs_nsds + args: + chdir: /root/.autocluster/ + creates: gpfs_nsds + +- name: check if GPFS NSDs created file exists + stat: + path: /root/.autocluster/gpfs_nsds_created + register: gpfs_nsds_created + +- name: create GPFS NSDs + command: mmcrnsd -F gpfs_nsds + args: + chdir: /root/.autocluster/ + when: not gpfs_nsds_created.stat.exists + +- name: flag GPFS NSDs as created + file: + path: /root/.autocluster/gpfs_nsds_created + state: touch + +- name: check if GPFS filesystem created file exists + stat: + path: /root/.autocluster/gpfs_fs_created + register: gpfs_fs_created + +- name: create GPFS filesystem + command: > + mmcrfs gpfs0 -F gpfs_nsds + -A yes -Q yes -D nfs4 -B 64k -k nfs4 -n 32 -E yes -S no + -T {{ clusterfs.mountpoint}} -i 512 + args: + chdir: /root/.autocluster/ + when: not gpfs_fs_created.stat.exists + +- name: flag GPFS filesystem as created + file: + path: /root/.autocluster/gpfs_fs_created + state: touch + +- name: check if GPFS filesystem mounted file exists + stat: + path: /root/.autocluster/gpfs_fs_mounted + register: gpfs_fs_mounted + +- name: mount GPFS filesystem + command: mmmount gpfs0 -a + when: not gpfs_fs_mounted.stat.exists + +- name: wait until GPFS filesystem is mounted + command: findmnt {{ clusterfs.mountpoint }} + register: result + until: result.rc == 0 + retries: 12 + delay: 5 + when: not gpfs_fs_mounted.stat.exists + +- name: flag GPFS filesystem as mounted + file: + path: /root/.autocluster/gpfs_fs_mounted + state: touch diff --git a/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs.yml b/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs.yml new file mode 100644 index 0000000..c498443 --- /dev/null +++ b/ansible/node/roles/storage/tasks/generic/clusterfs-gpfs.yml @@ -0,0 +1,20 @@ +--- +- name: create cluster filesystem mountpoint + file: + path: "{{clusterfs.mountpoint}}" + state: directory + +- name: create cluster filesystem automount directory + file: + path: "{{clusterfs.mountpoint}}/automount" + state: directory + +- name: make cluster filesystem mountpoint immutable + shell: > + if ! findmnt "{{clusterfs.mountpoint}}"; then + chattr +i "{{clusterfs.mountpoint}}" + fi + +- import_tasks: clusterfs-gpfs-once.yml + run_once: true + when: nodes[ansible_hostname].has_shared_storage diff --git a/ansible/node/roles/storage/tasks/main.yml b/ansible/node/roles/storage/tasks/main.yml new file mode 100644 index 0000000..07a5ad1 --- /dev/null +++ b/ansible/node/roles/storage/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- include_tasks: generic/{{ task }}.yml + with_list: + - clusterfs-{{ clusterfs.type }} + loop_control: + loop_var: task diff --git a/ansible/node/roles/storage/templates/gpfs_nodes.j2 b/ansible/node/roles/storage/templates/gpfs_nodes.j2 new file mode 100644 index 0000000..5a9ecd7 --- /dev/null +++ b/ansible/node/roles/storage/templates/gpfs_nodes.j2 @@ -0,0 +1,33 @@ +# GPFS nodes file generated by autocluster +{# #} +{# Count dedicated storage nodes, find first CTDB node #} +{# #} +{% set num_storage_nodes = 0 %} +{% set first_ctdb_node = "" %} +{% for hostname, n in nodes | dictsort %} +{% if n.has_shared_storage %} +{% if n.is_ctdb_node %} +{% if not first_ctdb_node %} +{% set first_ctdb_node = hostname %} +{% endif %} +{% else %} +{% set num_storage_nodes = num_storage_nodes + 1 %} +{% endif %} +{% endif %} +{% endfor %} +{# #} +{# Generate GPFS nodes file lines #} +{# #} +{% for hostname, n in nodes | dictsort %} +{% if n.is_ctdb_node %} +{% if hostname == first_ctdb_node %} +{{ hostname }}:manager-quorum: +{% elif num_storage_nodes > 0 %} +{{ hostname }}:manager: +{% else %} +{{ hostname }}:manager-quorum: +{% endif %} +{% elif n.has_shared_storage %} +{{ hostname }}:manager-quorum: +{% endif %} +{% endfor %} diff --git a/ansible/node/roles/storage/templates/gpfs_primary_secondary.j2 b/ansible/node/roles/storage/templates/gpfs_primary_secondary.j2 new file mode 100644 index 0000000..aec7a37 --- /dev/null +++ b/ansible/node/roles/storage/templates/gpfs_primary_secondary.j2 @@ -0,0 +1,19 @@ +{# #} +{# Count dedicated storage nodes #} +{# #} +{% set num_storage_nodes = 0 %} +{% for hostname, n in nodes | dictsort %} +{% if n.has_shared_storage and not n.is_ctdb_node %} +{% set num_storage_nodes = num_storage_nodes + 1 %} +{% endif %} +{% endfor %} +{# #} +{# Write a single line containing "primary secondary" #} +{# #} +{% if num_storage_nodes >= 2 %} +{{ groups['storage-nodes'][0] }} {{ groups['storage-nodes'][1] }} +{% elif num_storage_nodes == 1 %} +{{ groups['storage-nodes'][0] }} {{ groups['nas-nodes'][0] }} +{% else %} +{{ groups['nas-nodes'][0] }} {{ groups['nas-nodes'][1] }} +{% endif %} diff --git a/ansible/node/site.yml b/ansible/node/site.yml new file mode 100644 index 0000000..cfbc3f0 --- /dev/null +++ b/ansible/node/site.yml @@ -0,0 +1,8 @@ +--- +- import_playbook: ad.yml +- import_playbook: base.yml +- import_playbook: build.yml +- import_playbook: cbuild.yml +- import_playbook: storage.yml +- import_playbook: test.yml +- import_playbook: nas.yml diff --git a/ansible/node/storage.yml b/ansible/node/storage.yml new file mode 100644 index 0000000..94032ec --- /dev/null +++ b/ansible/node/storage.yml @@ -0,0 +1,8 @@ +--- +- hosts: storage-nodes + remote_user: root + + roles: + - common + - clusterfs + - storage diff --git a/ansible/node/test.yml b/ansible/node/test.yml new file mode 100644 index 0000000..a28f56d --- /dev/null +++ b/ansible/node/test.yml @@ -0,0 +1,8 @@ +--- +- hosts: test-nodes + remote_user: root + + roles: + - common + - nasrepos + - ctdb -- cgit